Compare commits
235 Commits
08b75a7b93
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee7d51ff4b | ||
| b72a4b62c2 | |||
| 588ba4698c | |||
| cdee67e203 | |||
| 9e577a1abe | |||
| 881c77c383 | |||
| b3e200e9d6 | |||
| 7da658ec0f | |||
| de4bf24f5b | |||
| 8a7c8ad75a | |||
| 69e6e0659f | |||
| d2b8690c0a | |||
| 2147fdbb02 | |||
| 761045bd62 | |||
|
|
50f193b2db | ||
| e30641250e | |||
| 0c858eaba1 | |||
| c4f00b4328 | |||
| f984ec736d | |||
| 454e474564 | |||
|
|
8f06ffbed9 | ||
|
|
c15231193b | ||
|
|
bd51a307e8 | ||
|
|
f948bbc974 | ||
|
|
6fff2d19f5 | ||
|
|
fb6a44f132 | ||
|
|
c5800c3e14 | ||
|
|
1a4d5ade8f | ||
|
|
331c908cb8 | ||
|
|
c5d71a4da7 | ||
|
|
452e84b2ca | ||
|
|
1e00424274 | ||
| e19bd34d0c | |||
| f8e6992cea | |||
| 28d6cb1a44 | |||
| 0ca87cfbee | |||
| 13d705639c | |||
|
|
c690004aca | ||
|
|
a90599279b | ||
|
|
9916c56721 | ||
|
|
5c4f74da8f | ||
| f7e6b20b25 | |||
|
|
9fd4f2cce8 | ||
|
|
c8f81a0315 | ||
|
|
0c53f9fae6 | ||
|
|
ce14ed07fc | ||
|
|
eaf957da50 | ||
|
|
4ddb8de08e | ||
| c25fa1943a | |||
|
|
19efadfa1d | ||
|
|
750bde5b38 | ||
|
|
de31b20e72 | ||
|
|
c6e57c9475 | ||
|
|
98eddc7b64 | ||
|
|
e2b9906429 | ||
|
|
99be082770 | ||
| 029b3fe3cd | |||
|
|
70daf74b8d | ||
|
|
307a492847 | ||
|
|
ee106a077c | ||
|
|
fd798e83c3 | ||
|
|
477ecb7c4d | ||
| 6e9f8dddb9 | |||
|
|
133cea8089 | ||
|
|
e966afb059 | ||
| be872a008e | |||
|
|
b60d27a7fe | ||
|
|
ff0eeb0fce | ||
| 5b30bee2a9 | |||
|
|
89e71d95a5 | ||
|
|
21a3a248b2 | ||
|
|
36616d567f | ||
|
|
44432a300b | ||
|
|
11c8552978 | ||
|
|
211c2ee576 | ||
|
|
27b59de7aa | ||
|
|
afe2c69d3e | ||
|
|
5cf5ed1278 | ||
|
|
38fa8363e5 | ||
|
|
b7188cbf4b | ||
|
|
7a7a68753a | ||
|
|
6d940ffda8 | ||
|
|
988513d86b | ||
|
|
bf8e39046a | ||
|
|
913c24a33f | ||
|
|
f50cfc1ca7 | ||
|
|
3094498fc6 | ||
|
|
a0fe5dd71d | ||
|
|
999c22b420 | ||
|
|
3f8e6f31ae | ||
|
|
1333f1a651 | ||
|
|
8f8632e65e | ||
|
|
e3f3040073 | ||
|
|
a99d2a59c1 | ||
|
|
ea5551e41f | ||
|
|
15899ef0c7 | ||
|
|
9c4d268e3d | ||
| 94f7e151c0 | |||
| 4671bb0abd | |||
|
|
bb5278ebd5 | ||
|
|
9c827793e0 | ||
|
|
5207676ada | ||
|
|
5861b6af76 | ||
|
|
7c125e18d1 | ||
|
|
6237cbec79 | ||
|
|
d0242b29ce | ||
|
|
7eb6b5769e | ||
|
|
dc0ed1b79d | ||
|
|
96094332ef | ||
|
|
1e40fa679c | ||
|
|
2b60851ea3 | ||
|
|
51ecfe7ee1 | ||
|
|
f0a02bc746 | ||
|
|
ff91ef36e3 | ||
|
|
09f76ab8ab | ||
|
|
d05df71e5c | ||
|
|
0c2b8da54f | ||
|
|
f2b2c021f8 | ||
|
|
72625870bf | ||
|
|
485c2090a1 | ||
|
|
15ffd74a3e | ||
|
|
ef23cc5f9a | ||
|
|
c9e3f1782c | ||
|
|
de4a821af5 | ||
|
|
32268cd2a9 | ||
|
|
9fd1578a7e | ||
|
|
75aa177430 | ||
|
|
1116647ec2 | ||
|
|
9cd1d56a72 | ||
|
|
96f7295f96 | ||
|
|
901042b562 | ||
|
|
2036ae59f4 | ||
|
|
178d0f37ab | ||
|
|
a7b3cda711 | ||
|
|
ce96666422 | ||
|
|
9b86646411 | ||
|
|
6f09d7a865 | ||
|
|
80d42edbc1 | ||
|
|
80f76cf8ac | ||
|
|
1aeb5b4c36 | ||
|
|
b497a00693 | ||
|
|
277035cf55 | ||
|
|
61f97c908e | ||
|
|
6b45e5f846 | ||
|
|
7cde1aaeff | ||
|
|
96e105213e | ||
|
|
d0ceacf5ef | ||
|
|
db62df1090 | ||
|
|
51d864512f | ||
|
|
ec984efd3d | ||
|
|
5c065162dd | ||
|
|
255cce967a | ||
|
|
7fb53cc776 | ||
|
|
a7eebc7ac7 | ||
|
|
aab64d1ed7 | ||
|
|
2822c44f8e | ||
|
|
3b2ab5189a | ||
|
|
240928b74b | ||
|
|
d05be5fa35 | ||
|
|
840b9e9057 | ||
|
|
5199f9ea5e | ||
| 456cee3067 | |||
| 9cbece1ab8 | |||
| b97d611c79 | |||
| 56969eff40 | |||
|
|
040abb21e0 | ||
|
|
ad89dc6c4c | ||
|
|
00b2b13244 | ||
|
|
feda70a9b2 | ||
|
|
95e4647899 | ||
|
|
65e19bcdda | ||
|
|
4e00e4676b | ||
|
|
3c94831315 | ||
|
|
51551534f1 | ||
| 08f624fd4d | |||
|
|
0f1f9c72ec | ||
|
|
6f67751985 | ||
|
|
76fbc34b5d | ||
|
|
e68b051f83 | ||
|
|
2506441cfd | ||
|
|
017fbc8857 | ||
|
|
9a645a516c | ||
| 2f9f37775e | |||
| 59c521ee7d | |||
| f28c8f337a | |||
|
|
2c54961330 | ||
|
|
7f8546f99b | ||
|
|
2cf3ca33bd | ||
|
|
bffa7d713e | ||
|
|
e189fd1b5d | ||
|
|
ab4fe843e4 | ||
|
|
4c5d0ded39 | ||
|
|
5a13da4d58 | ||
|
|
db6884d245 | ||
|
|
8ab6930155 | ||
|
|
c44114c672 | ||
|
|
486fb7e6c9 | ||
|
|
7081caa7ff | ||
|
|
79d8a3cf3b | ||
|
|
af265e9cfe | ||
|
|
3feeb6a412 | ||
|
|
19db9793df | ||
|
|
73b43037ad | ||
|
|
0eeda2655a | ||
|
|
ca0dc63f6f | ||
|
|
5a4f897d10 | ||
|
|
c308b967fd | ||
|
|
59b371fdd3 | ||
|
|
1498c42a41 | ||
| 9b82858000 | |||
| e6d2809585 | |||
|
|
1f65e1cd01 | ||
|
|
1c4b06eae8 | ||
|
|
8a0ab3a7c4 | ||
| b6c9e66cc9 | |||
|
|
2466258187 | ||
|
|
4a855c986b | ||
| 11f2f53a3e | |||
|
|
6315f503a6 | ||
|
|
c7b4c6acfb | ||
|
|
0d8ca693a3 | ||
| 4ef91afbf8 | |||
|
|
a11a00eb25 | ||
|
|
c58aec524d | ||
|
|
43c60bac5d | ||
|
|
f8a1bd5bd7 | ||
| 51594b5ee4 | |||
| a7418e9bdf | |||
| e956432311 | |||
|
|
93a76968ce | ||
|
|
2edef6eb76 | ||
|
|
3d62c04c19 | ||
|
|
60d0913f48 | ||
|
|
1e64eed0c1 | ||
|
|
4bd577963b |
204
README.md
204
README.md
@@ -2,16 +2,210 @@
|
||||
|
||||
Utilities to use with smeserver on Koozali.org GITEA instance
|
||||
|
||||
Just a repackaging of Brian Read's tools with some modifications for the new git structure and some tidy-up of the ini file and debug statements
|
||||
Just a repackaging of some of Brian Read's tools with some modifications for the new git structure and some tidy-up of the ini file and debug statements
|
||||
|
||||
It's a good idea to have the scripts somewhere in your path (some do call others). You can put them in ~/bin (you may need to create this if it doesn't exist)
|
||||
|
||||
## config
|
||||
sample ~/.smegit/config or /etc/smegit.ini file - fill in your details\
|
||||
It will use the user config first and system ini, if user config does not exist
|
||||
|
||||
## git-cvs2git.sh
|
||||
copy current cvs version of a package across to git in new structure
|
||||
|
||||
git-cvs2git.sh <repository> <organisation> [<local>]
|
||||
|
||||
* \<repository\> repository (package) to be migrated (e.g. smeserver-yum)
|
||||
* \<organisation\> can ONLY be smeserver or smecontribs
|
||||
|
||||
optional parameters, can appear in any order
|
||||
|
||||
* \<local\> will migrate into your local GITEA (in config), otherwise remote GITEA
|
||||
* \<debug\> run in debug mode
|
||||
|
||||
## git-get-and-build-repo.sh
|
||||
bring down current git repository and run mockbuild
|
||||
|
||||
## git-mirror-rep.sh
|
||||
create mirror of src.koozali.org repository in a local GITEA instance
|
||||
git-get-and-build.sh <repository> <organisation> [branch=<branch> <local> <debug>]
|
||||
|
||||
* \<branch=<branch\> will bring back a specific branch, otherwise Master
|
||||
* \<repository\> repository (package) to be built (e.g. smeserver-yum)
|
||||
* \<organisation\> can be any organisation or user on the remote GITEA instance
|
||||
|
||||
optional parameters, can appear in any order
|
||||
|
||||
* \<local\> will build from local GITEA (in config), otherwise from remote GITEA
|
||||
* \<debug\> run in debug mode
|
||||
|
||||
## git-migrate-repo.sh
|
||||
create mirror or copy of src.koozali.org repository in a local GITEA instance
|
||||
|
||||
git-migrate-repo.sh <repository> <organisation> [<target organisation> <copy|mirror> <local> <debug>]
|
||||
|
||||
* \<repository\> repository (package) to be copied (e.g. smeserver-yum)
|
||||
* \<organisation\> can be any organisation or user on the remote GITEA instance
|
||||
|
||||
optional parameters, can appear in any order
|
||||
|
||||
* \<target organisation\> within your local GITEA, otherwise local user - must exist already
|
||||
* \<copy|mirror\> will create local repo as either a copy or a mirror of the remote repo (default = copy)
|
||||
* \<local\> use local GITEA as source (i.e. copy between organisations on local GITEA)
|
||||
* \<debug\> run in debug mode
|
||||
|
||||
## git-transfer-repo.sh
|
||||
Transfer a repo to a different user (or organisation)
|
||||
|
||||
git-transfer-repo.sh <repository> <source organization> <target organisation> [<local> <force> <debug> <silent>]
|
||||
|
||||
* \<repository\> repository name to be transferred (e.g. smeserver-clamav)
|
||||
* \<source organisation\> to be transferred from (any valid organisation or user)
|
||||
* \<target organisation\> to be transferred to (any valid organisation or user - you need owner privileges)
|
||||
|
||||
optional parameters, can appear in any order
|
||||
|
||||
\<local\> will use parameters set for local repository, else it will use remote
|
||||
\<force\> will automagically delete an existing target repo, otherwise it will prompt
|
||||
\<debug\> run in debug mode
|
||||
\<silent\> suppress success message
|
||||
|
||||
## git-retag.sh
|
||||
Create a new tag based on %version-%release in spec file (without trailing el7.sme) and optionally remove old tags
|
||||
|
||||
git-retag.sh <repository> <organisation> [<local> <debug> <noisy>]
|
||||
|
||||
* \<repository\> repository to be retagged
|
||||
* \<organisation\> organisation\owner that the repository belongs to
|
||||
|
||||
optional parameters, can appear in any order
|
||||
|
||||
* \<purge\> will remove all existing tags
|
||||
* \<local\> will use parameters set for local repository, else it will use remote
|
||||
* \<debug\> run with debug output
|
||||
* \<noisy\> will will print a line showing how it was called
|
||||
|
||||
## parse-list.sh
|
||||
Parse a list of parameters and execute script with those parameters
|
||||
|
||||
parse-list.sh <param file|org='organisation'> <script> [<local> <noisy> <review> <additional*>]
|
||||
|
||||
* \<param file\|org='organisation'> name of file containing parameters or organisation which will be used to generate a list of all repos for input to \<script\>
|
||||
* \<script\> script to run (e.g. rename-e-smith-pkg.sh)
|
||||
|
||||
optional params can appear in any order
|
||||
|
||||
* \<local\> used with org= and will use local GITEA instance, default remote - will be passed to \<script\>
|
||||
* \<noisy\> show line being executed
|
||||
* \<review\> show line to be executed, but NOT executing
|
||||
* \<additional\> additional params to be passed (up to 3) e.g. debug,force,local
|
||||
|
||||
### example:
|
||||
|
||||
parse-list.sh org=smeserver git-migrate-repo.sh review
|
||||
|
||||
will echo the command that would be run for each repo in the smeserver organisation on the remote GITEA instance
|
||||
|
||||
git-migrate-repo.sh perl-Moo smeserver
|
||||
git-migrate-repo.sh buildsys-macros smeserver
|
||||
git-migrate-repo.sh clamav smeserver
|
||||
...
|
||||
|
||||
## git-post-create-repo.sh
|
||||
Update a repo created from a template (contribs,base or 3rd party) with things not able to be updated from the template:
|
||||
|
||||
* \<repository\> repository (package) to be editted (e.g. smeserver-yum)
|
||||
* \<organisation\> can be any organisation or user on the remote or local GITEA instance
|
||||
|
||||
optional:
|
||||
|
||||
* \<local\> will migrate into your local GITEA (in config), otherwise remote GITEA
|
||||
|
||||
Does:
|
||||
|
||||
Rename spec file
|
||||
Set current date in change log
|
||||
Set Wiki and Issues links external (SME Wiki and Bugzilla)
|
||||
|
||||
## git-make-release.sh
|
||||
Create a release and upload the rpm (src and bin) as attachments to that release
|
||||
|
||||
* \<repository\> repository (package) to be editted (e.g. smeserver-yum)
|
||||
* \<draft | prerelease> create draft or prerelease else it will create full stable release
|
||||
* \<organisation\> can be any organisation or user on the remote or local GITEA instance
|
||||
* \<release-tag\> will have "SME" added to the front of it (so e.g. 10.2 -> SME10.2)
|
||||
|
||||
optional: (in any order)
|
||||
|
||||
* \<local\> used with org= and will use local GITEA instance, default remote - will be passed to \<script\>
|
||||
* \<noisy\> show line being executed
|
||||
* \<debug\> run in debug mode
|
||||
* \<draft\> create a draft release
|
||||
* \<prerelease\> create a pre-release
|
||||
|
||||
Note that no release type will give a full stable release
|
||||
|
||||
Does:
|
||||
|
||||
Create the release (deleting one that is the same tag),
|
||||
Then uploads the .src.rpm and .rpm as an attachment (deleting any one of the same name)
|
||||
|
||||
## git-list-all-org-repos.sh
|
||||
List the repos in any one organisation and optionally show the release and some associated fields
|
||||
|
||||
* \<organisation\> can be any organisation or user on the remote or local GITEA instance
|
||||
|
||||
optional: (in any order)
|
||||
|
||||
* \<local\> used with org= and will use local GITEA instance, default remote - will be passed to \<script\>
|
||||
* \<noisy\> show line being executed
|
||||
* \<debug\> run in debug mode
|
||||
* \<draftrelease\> Show all draft releases
|
||||
* \<prerelease\> Show all prereleases
|
||||
* \<release\> Show all full releases
|
||||
* \<allreleases\> Show all releases
|
||||
* \<cloneurl\> Show the url to use to clone this repo
|
||||
* \<zipurl\> Show the url to get the zipped contents of the repo
|
||||
* \<asseturls\> Show the URLs of the assets associated with the release
|
||||
|
||||
Does:
|
||||
|
||||
Display a "table" of each repo and the optional extras requested.
|
||||
|
||||
## git-update-release-in-one-repo.sh
|
||||
Update the release (draft/prerelease/release)
|
||||
|
||||
* \<organisation\> can be any organisation or user on the remote or local GITEA instance
|
||||
* \<repo\> name of the repo (package)
|
||||
* \<releasetag\> Full tag of the release (inc SME if applicable) OR
|
||||
* \<id\>
|
||||
* draft|prerelease|release
|
||||
|
||||
|
||||
optional: (in any order)
|
||||
|
||||
* \<local\> used with org= and will use local GITEA instance, default remote - will be passed to \<script\>
|
||||
* \<debug\> run in debug mode
|
||||
|
||||
Does:
|
||||
|
||||
Resets the release specified to the type specified.
|
||||
|
||||
## git-get-latest-tag.sh
|
||||
|
||||
Return the newest tag for the repo
|
||||
|
||||
* \<repo\> name of the repo (package)
|
||||
* \<organisation\> can be any organisation or user on the remote or local GITEA instance
|
||||
|
||||
## github-make-push-mirror.sh
|
||||
|
||||
Create a repo on github.com and add a push mirror entry to the equivalent gitea repo.
|
||||
|
||||
* \<repo\> Name of the repo
|
||||
* \<organisation\> Name of the organisation in GITEA
|
||||
* \<github organisation\> Name of the organisation in GITHUB
|
||||
|
||||
Note that .smegit/conf needd GITHUBTOKEN and GITHUBLOGIN the token must have the necessary permissions. Either fine-grain token or one of the orginal tokens. Created through settings/developer tools/api tokens on github.com.
|
||||
|
||||
Also need to login in to github using `gh auth login` before running the command.
|
||||
|
||||
|
||||
## git-mirror-org.sh
|
||||
create mirrors of all repos for an organisation in a local GITEA instance
|
||||
|
||||
161
TestPrograms/bz_smoke_test.py
Normal file
161
TestPrograms/bz_smoke_test.py
Normal file
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import base64
|
||||
import httpx
|
||||
import datetime as dt
|
||||
from datetime import timezone
|
||||
|
||||
BASE_URL = os.environ.get("BUGZILLA_BASE_URL", "https://bugs.koozali.org").rstrip("/")
|
||||
RPC_URL = f"{BASE_URL}/jsonrpc.cgi"
|
||||
|
||||
# Auth: prefer API key. If not set, use username/password to obtain a session token.
|
||||
API_KEY = os.environ.get("BUGZILLA_API_KEY", "").strip()
|
||||
USER = os.environ.get("BUGZILLA_USER", "").strip() # usually your Bugzilla login (often an email)
|
||||
PASSWORD = os.environ.get("BUGZILLA_PASSWORD", "").strip()
|
||||
|
||||
# Required fields (must be provided via ENV)
|
||||
PRODUCT = os.environ.get("BUGZILLA_PRODUCT", "").strip()
|
||||
VERSION_FIELD = os.environ.get("BUGZILLA_VERSION", "").strip()
|
||||
|
||||
# Optional fields
|
||||
COMPONENT = os.environ.get("BUGZILLA_COMPONENT", "e-smith-*/smeserver-* packages").strip()
|
||||
|
||||
# Behavior toggles
|
||||
ATTACH_DIFF = os.environ.get("BUGZILLA_ATTACH_DIFF", "true").lower() == "true"
|
||||
ATTACH_FILE = os.environ.get("BUGZILLA_ATTACH_FILE", "").strip() # optional path to a local patch file
|
||||
RESOLVE_AFTER = os.environ.get("BUGZILLA_RESOLVE_AFTER", "false").lower() == "true"
|
||||
RESOLUTION = os.environ.get("BUGZILLA_RESOLUTION", "INVALID")
|
||||
|
||||
TIMEOUT = 60 # seconds
|
||||
|
||||
def require_env(name: str, value: str):
|
||||
if not value:
|
||||
print(f"FAILED: required environment variable {name} is not set.")
|
||||
sys.exit(2)
|
||||
|
||||
def now_rfc3339():
|
||||
return dt.datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
|
||||
|
||||
def rpc_call(method: str, params: dict, req_id: int = 1) -> dict:
|
||||
body = {"method": method, "params": [params], "id": req_id}
|
||||
r = httpx.post(RPC_URL, headers={"Content-Type": "application/json"}, json=body, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
if data.get("error"):
|
||||
err = data["error"]
|
||||
raise RuntimeError(f"RPC {method} error {err.get('code')}: {err.get('message')}")
|
||||
return data.get("result", {})
|
||||
|
||||
def rpc(method: str, params: dict, req_id: int = 1, token: str | None = None) -> dict:
|
||||
# Inject auth each call
|
||||
if API_KEY:
|
||||
params = dict(params, Bugzilla_api_key=API_KEY)
|
||||
elif token:
|
||||
params = dict(params, Bugzilla_token=token)
|
||||
else:
|
||||
raise RuntimeError("No API key or session token available for Bugzilla")
|
||||
return rpc_call(method, params, req_id=req_id)
|
||||
|
||||
def login_get_token() -> str:
|
||||
if not (USER and PASSWORD):
|
||||
raise RuntimeError("BUGZILLA_USER and BUGZILLA_PASSWORD must be set if no API key is provided")
|
||||
result = rpc_call("User.login", {"login": USER, "password": PASSWORD}, req_id=0)
|
||||
token = result.get("token")
|
||||
if not token:
|
||||
raise RuntimeError("Login did not return a token")
|
||||
return token
|
||||
|
||||
def create_bug(token: str | None) -> int:
|
||||
summary = f"[Mirror smoke test] Confirm Bugzilla writes OK @ {now_rfc3339()}"
|
||||
description = (
|
||||
"Automated smoke test from mirror service.\n"
|
||||
"Validates JSON-RPC create/comment/attach flows. This issue can be resolved after verification."
|
||||
)
|
||||
params = {
|
||||
"product": PRODUCT,
|
||||
"component": COMPONENT,
|
||||
"version": VERSION_FIELD, # REQUIRED per your request
|
||||
"summary": summary,
|
||||
"description": description,
|
||||
}
|
||||
res = rpc("Bug.create", params, req_id=1, token=token)
|
||||
bug_id = res.get("id") or (res.get("bugs") and res["bugs"][0]["id"])
|
||||
if not bug_id:
|
||||
raise RuntimeError(f"Unexpected Bug.create result: {res}")
|
||||
return int(bug_id)
|
||||
|
||||
def add_comment(bug_id: int, token: str | None, text: str):
|
||||
rpc("Bug.add_comment", {"id": bug_id, "comment": text}, req_id=2, token=token)
|
||||
|
||||
def add_attachment(bug_id: int, token: str | None, filename: str, summary: str, content: bytes):
|
||||
b64 = base64.b64encode(content).decode("ascii")
|
||||
params = {
|
||||
"ids": [bug_id],
|
||||
"data": b64,
|
||||
"file_name": filename,
|
||||
"summary": summary,
|
||||
"content_type": "text/x-patch",
|
||||
"is_patch": True,
|
||||
}
|
||||
rpc("Bug.add_attachment", params, req_id=3, token=token)
|
||||
|
||||
def resolve_bug(bug_id: int, token: str | None, resolution: str):
|
||||
params = {"ids": [bug_id], "status": "RESOLVED", "resolution": resolution}
|
||||
rpc("Bug.update", params, req_id=4, token=token)
|
||||
|
||||
def main():
|
||||
# Require PRODUCT and VERSION from env
|
||||
require_env("BUGZILLA_PRODUCT", PRODUCT)
|
||||
require_env("BUGZILLA_VERSION", VERSION_FIELD)
|
||||
|
||||
print(f"Bugzilla JSON-RPC endpoint: {RPC_URL}")
|
||||
# Optional version check
|
||||
try:
|
||||
ver = rpc_call("Bugzilla.version", {}, req_id=99).get("version", "<unknown>")
|
||||
print("Bugzilla version:", ver)
|
||||
except Exception as e:
|
||||
print("Bugzilla.version call failed (continuing):", e)
|
||||
|
||||
token = None
|
||||
if not API_KEY:
|
||||
print("No API key provided; logging in to obtain session token...")
|
||||
token = login_get_token()
|
||||
print("Got session token.")
|
||||
|
||||
print(f"Creating bug in product={PRODUCT} component={COMPONENT} version={VERSION_FIELD} ...")
|
||||
bug_id = create_bug(token)
|
||||
bug_url = f"{BASE_URL}/show_bug.cgi?id={bug_id}"
|
||||
print(f"Created bug {bug_id}: {bug_url}")
|
||||
|
||||
print("Adding a comment ...")
|
||||
add_comment(bug_id, token, f"Automated comment at {now_rfc3339()} (smoke test).")
|
||||
print("Comment added.")
|
||||
|
||||
if ATTACH_DIFF:
|
||||
print("Adding attachment (patch) ...")
|
||||
if ATTACH_FILE:
|
||||
with open(ATTACH_FILE, "rb") as f:
|
||||
content = f.read()
|
||||
filename = os.path.basename(ATTACH_FILE)
|
||||
else:
|
||||
content = b"diff --git a/file.txt b/file.txt\n--- a/file.txt\n+++ b/file.txt\n@@\n+hello from JSON-RPC smoke test\n"
|
||||
filename = "dummy.patch"
|
||||
add_attachment(bug_id, token, filename, "Automated dummy patch", content)
|
||||
print("Attachment added.")
|
||||
|
||||
if RESOLVE_AFTER:
|
||||
print(f"Resolving bug as RESOLVED/{RESOLUTION} ...")
|
||||
resolve_bug(bug_id, token, RESOLUTION)
|
||||
print("Bug resolved.")
|
||||
|
||||
print("SUCCESS. Bugzilla JSON-RPC write path verified.")
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
sys.exit(main())
|
||||
except Exception as e:
|
||||
print("FAILED:", e)
|
||||
sys.exit(1)
|
||||
107
TestPrograms/post_pr_event.py
Normal file
107
TestPrograms/post_pr_event.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
import httpx
|
||||
import sqlite3
|
||||
import os
|
||||
import time
|
||||
|
||||
def sign(secret: str, body: bytes) -> str:
|
||||
return "sha256=" + hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||||
|
||||
def seed_state(state_path: str, pr_key: str, bug_id: int = 1):
|
||||
# Create/seed the PR->Bug mapping so the server skips Bugzilla and allows synchronize to run mirroring.
|
||||
os.makedirs(os.path.dirname(state_path) or ".", exist_ok=True)
|
||||
conn = sqlite3.connect(state_path)
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
CREATE TABLE IF NOT EXISTS pr_map (
|
||||
pr_key TEXT PRIMARY KEY,
|
||||
bug_id INTEGER NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
now = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
|
||||
cur.execute("""
|
||||
INSERT INTO pr_map (pr_key, bug_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(pr_key) DO UPDATE SET bug_id=excluded.bug_id, updated_at=excluded.updated_at
|
||||
""", (pr_key, bug_id, now, now))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def build_payload(owner_repo: str, pr_number: int, title: str, body: str,
|
||||
base_branch: str, base_sha: str, head_branch: str, head_sha: str,
|
||||
gh_user: str):
|
||||
owner, repo = owner_repo.split("/", 1)
|
||||
return {
|
||||
"action": "synchronize",
|
||||
"repository": {
|
||||
"full_name": owner_repo,
|
||||
"owner": {"login": owner},
|
||||
"name": repo,
|
||||
},
|
||||
"pull_request": {
|
||||
"number": pr_number,
|
||||
"html_url": f"https://github.com/{owner_repo}/pull/{pr_number}",
|
||||
"title": title,
|
||||
"body": body,
|
||||
"user": {"login": gh_user, "html_url": f"https://github.com/{gh_user}"},
|
||||
"base": {"ref": base_branch, "sha": base_sha},
|
||||
"head": {"ref": head_branch, "sha": head_sha, "repo": {"owner": {"login": gh_user}}},
|
||||
"created_at": "2025-09-20T12:34:56Z",
|
||||
"labels": [],
|
||||
},
|
||||
}
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description="Post a signed GitHub PR webhook to a running webhook_endpoint server")
|
||||
ap.add_argument("--server", required=True, help="Base URL of running server, e.g. http://127.0.0.1:8081")
|
||||
ap.add_argument("--secret", required=True, help="Webhook secret (must match server WEBHOOK_SECRET)")
|
||||
ap.add_argument("--repo-full", required=True, help="GitHub owner/repo (must match real repo hosting the PR)")
|
||||
ap.add_argument("--pr", type=int, required=True, help="GitHub PR number to mirror")
|
||||
ap.add_argument("--title", default="Test PR from harness")
|
||||
ap.add_argument("--body", default="Harness test body.")
|
||||
ap.add_argument("--base-branch", default="master")
|
||||
ap.add_argument("--base-sha", default="9f8e7d6cafebabe0000deadbeef0000000000000")
|
||||
ap.add_argument("--head-branch", default="feature/test")
|
||||
ap.add_argument("--head-sha", default="a1b2c3ddeeddbb0000deadbeef0000000000000")
|
||||
ap.add_argument("--gh-user", default="octocat", help="GitHub login of PR author")
|
||||
ap.add_argument("--state-path", required=True, help="Path to the server's STATE_PATH SQLite file")
|
||||
ap.add_argument("--seed", action="store_true", help="Seed the state DB so Bugzilla is skipped")
|
||||
args = ap.parse_args()
|
||||
|
||||
pr_key = f"{args.repo_full}#{args.pr}"
|
||||
if args.seed:
|
||||
print(f"Seeding PR mapping in {args.state_path}: {pr_key} -> bug_id=1")
|
||||
seed_state(args.state_path, pr_key, bug_id=1)
|
||||
|
||||
payload = build_payload(
|
||||
owner_repo=args.repo_full,
|
||||
pr_number=args.pr,
|
||||
title=args.title,
|
||||
body=args.body,
|
||||
base_branch=args.base_branch,
|
||||
base_sha=args.base_sha,
|
||||
head_branch=args.head_branch,
|
||||
head_sha=args.head_sha,
|
||||
gh_user=args.gh_user,
|
||||
)
|
||||
body_bytes = json.dumps(payload).encode("utf-8")
|
||||
sig = sign(args.secret, body_bytes)
|
||||
headers = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sig,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
url = args.server.rstrip("/") + "/webhook/github"
|
||||
print(f"POST {url} for {args.repo_full} PR #{args.pr}")
|
||||
r = httpx.post(url, data=body_bytes, headers=headers, timeout=30)
|
||||
print("Response:", r.status_code, r.text)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
101
TestPrograms/test-pr-creation.py
Normal file
101
TestPrograms/test-pr-creation.py
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
from fastapi.testclient import TestClient
|
||||
import types
|
||||
|
||||
# Import your server module
|
||||
import webhook_endpoint as srv
|
||||
|
||||
# Ensure safe test config toggles
|
||||
srv.GITHUB_DRY_RUN = True
|
||||
srv.BUGZILLA_ATTACH_DIFF = False
|
||||
# Enable mirroring flag and replace pr_mirror with a fake
|
||||
srv.GITEA_MIRROR_PR_ENABLE = True
|
||||
|
||||
# Fake PR mirror
|
||||
class FakePRMirror:
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
|
||||
def mirror(self, gh_owner: str, gh_repo: str, pr_number: int, pr_title: str, pr_body: str):
|
||||
self.calls.append({
|
||||
"owner": gh_owner,
|
||||
"repo": gh_repo,
|
||||
"pr_number": pr_number,
|
||||
"title": pr_title,
|
||||
"body": pr_body,
|
||||
})
|
||||
# Pretend we created PR #101 on Gitea
|
||||
return 101
|
||||
|
||||
fake_mirror = FakePRMirror()
|
||||
srv.pr_mirror = fake_mirror # monkeypatch the orchestrator in the module
|
||||
|
||||
# Also monkeypatch Bugzilla client to avoid real writes
|
||||
class FakeBZ:
|
||||
def create_bug(self, summary, description, component):
|
||||
return 99999
|
||||
def update_bug_fields(self, bug_id, fields):
|
||||
pass
|
||||
def add_attachment(self, *a, **k):
|
||||
pass
|
||||
def add_cc(self, *a, **k):
|
||||
pass
|
||||
def add_or_update_author_email_note(self, *a, **k):
|
||||
pass
|
||||
|
||||
srv.bz = FakeBZ()
|
||||
|
||||
# Build app client
|
||||
client = TestClient(srv.app)
|
||||
|
||||
def sign(secret: str, body: bytes) -> str:
|
||||
return "sha256=" + hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||||
|
||||
def payload(action="opened"):
|
||||
return {
|
||||
"action": action,
|
||||
"repository": {
|
||||
"full_name": "Koozali-SME-Server/smeserver-manager",
|
||||
"owner": {"login": "Koozali-SME-Server"},
|
||||
"name": "smeserver-manager",
|
||||
},
|
||||
"pull_request": {
|
||||
"number": 42,
|
||||
"html_url": "https://github.com/Koozali-SME-Server/smeserver-manager/pull/42",
|
||||
"title": "Improve logging",
|
||||
"body": "Please review.",
|
||||
"user": {"login": "octocat", "html_url": "https://github.com/octocat"},
|
||||
"base": {"ref": "master", "sha": "9f8e7d6cafebabe0000deadbeef0000000000000"},
|
||||
"head": {"ref": "feature/logs", "sha": "a1b2c3ddeeddbb0000deadbeef0000000000000", "repo": {"owner": {"login": "octocat"}}},
|
||||
"created_at": "2025-09-17T12:34:56Z",
|
||||
"labels": [{"name": "enhancement"}],
|
||||
},
|
||||
}
|
||||
|
||||
def run_test():
|
||||
body = json.dumps(payload("opened")).encode("utf-8")
|
||||
# Use the server's configured secret (or set one here)
|
||||
secret = srv.WEBHOOK_SECRET or "devsecret"
|
||||
headers = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sign(secret, body),
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
# If you run this without setting WEBHOOK_SECRET in env, also set it here:
|
||||
if not srv.WEBHOOK_SECRET:
|
||||
# monkeypatch the verify function to use our secret
|
||||
def verify_signature(secret_arg, *a, **k): return srv.verify_signature(secret, *a, **k)
|
||||
srv.verify_signature = verify_signature
|
||||
|
||||
resp = client.post("/webhook/github", data=body, headers=headers)
|
||||
print("Response:", resp.status_code, resp.json())
|
||||
print("Mirror calls recorded:", fake_mirror.calls)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json().get("status") in ("ok", "bugzilla_failed") # ok path returns "ok"
|
||||
assert any(c["pr_number"] == 42 for c in fake_mirror.calls), "Mirror was not invoked"
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_test()
|
||||
116
TestPrograms/test-pr-event-creation.py
Normal file
116
TestPrograms/test-pr-event-creation.py
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
# Simple webhook test sender for webhook_endpoint.py
|
||||
# Edit the CONFIG section and Run in Thonny. No CLI args needed.
|
||||
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
import httpx
|
||||
import sqlite3
|
||||
import os
|
||||
import time
|
||||
|
||||
# -------------- CONFIG (edit these) --------------
|
||||
|
||||
# Your running server (uvicorn webhook_endpoint:app ...)
|
||||
SERVER_BASE = "http://127.0.0.1:8081"
|
||||
|
||||
# Must match WEBHOOK_SECRET used by the server
|
||||
WEBHOOK_SECRET = "123456gfdsaqwertyuio"
|
||||
|
||||
# Path to the server's STATE_PATH (so we can seed the PR mapping to skip Bugzilla)
|
||||
STATE_PATH = "/tmp/webhook_state.sqlite"
|
||||
|
||||
# The real GitHub repo and PR you want to mirror (PR must exist on GitHub)
|
||||
REPO_FULL = "Koozali-SME-Server/smeserver-manager" # owner/repo
|
||||
PR_NUMBER = 9 # existing PR number on GitHub
|
||||
|
||||
# Cosmetic fields (not used for mirroring logic; placeholders are fine)
|
||||
PR_TITLE = "Test PR from harness"
|
||||
PR_BODY = "Harness test body."
|
||||
BASE_BRANCH = "master"
|
||||
BASE_SHA = "9f8e7d6cafebabe0000deadbeef0000000000000"
|
||||
HEAD_BRANCH = "feature/test"
|
||||
HEAD_SHA = "a1b2c3ddeeddbb0000deadbeef0000000000000"
|
||||
PR_AUTHOR = "octocat" # GitHub login of PR author (cosmetic)
|
||||
|
||||
# Seed the state DB so the server skips Bugzilla and treats event as "synchronize"
|
||||
SEED_STATE = True
|
||||
|
||||
# -------------------------------------------------
|
||||
|
||||
def sign(secret: str, body: bytes) -> str:
|
||||
return "sha256=" + hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||||
|
||||
def seed_state_db(state_path: str, pr_key: str, bug_id: int = 1):
|
||||
os.makedirs(os.path.dirname(state_path) or ".", exist_ok=True)
|
||||
conn = sqlite3.connect(state_path)
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
CREATE TABLE IF NOT EXISTS pr_map (
|
||||
pr_key TEXT PRIMARY KEY,
|
||||
bug_id INTEGER NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
now = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
|
||||
cur.execute("""
|
||||
INSERT INTO pr_map (pr_key, bug_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(pr_key) DO UPDATE SET bug_id=excluded.bug_id, updated_at=excluded.updated_at
|
||||
""", (pr_key, bug_id, now, now))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def build_payload():
|
||||
owner, repo = REPO_FULL.split("/", 1)
|
||||
return {
|
||||
"action": "synchronize", # use synchronize to trigger mirroring without Bugzilla create
|
||||
"repository": {
|
||||
"full_name": REPO_FULL,
|
||||
"owner": {"login": owner},
|
||||
"name": repo,
|
||||
},
|
||||
"pull_request": {
|
||||
"number": PR_NUMBER,
|
||||
"html_url": f"https://github.com/{REPO_FULL}/pull/{PR_NUMBER}",
|
||||
"title": PR_TITLE,
|
||||
"body": PR_BODY,
|
||||
"user": {"login": PR_AUTHOR, "html_url": f"https://github.com/{PR_AUTHOR}"},
|
||||
"base": {"ref": BASE_BRANCH, "sha": BASE_SHA},
|
||||
"head": {"ref": HEAD_BRANCH, "sha": HEAD_SHA, "repo": {"owner": {"login": PR_AUTHOR}}},
|
||||
"created_at": "2025-09-20T12:34:56Z",
|
||||
"labels": [],
|
||||
},
|
||||
}
|
||||
|
||||
def main():
|
||||
pr_key = f"{REPO_FULL}#{PR_NUMBER}"
|
||||
|
||||
if SEED_STATE:
|
||||
print(f"Seeding state: {STATE_PATH} -> {pr_key} = bug_id 1 (skips Bugzilla)")
|
||||
seed_state_db(STATE_PATH, pr_key, bug_id=1)
|
||||
|
||||
# Optional health check (won't fail the run)
|
||||
try:
|
||||
r = httpx.get(f"{SERVER_BASE.rstrip('/')}/healthz", timeout=3)
|
||||
print("Healthz:", r.status_code, r.text)
|
||||
except Exception as e:
|
||||
print("Healthz check failed (continuing):", e)
|
||||
|
||||
payload = build_payload()
|
||||
body = json.dumps(payload).encode("utf-8")
|
||||
headers = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sign(WEBHOOK_SECRET, body),
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
url = f"{SERVER_BASE.rstrip('/')}/webhook/github"
|
||||
print(f"POST {url} for {REPO_FULL} PR #{PR_NUMBER}")
|
||||
resp = httpx.post(url, data=body, headers=headers, timeout=30)
|
||||
print("Response:", resp.status_code, resp.text)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
262
TestPrograms/test_harness.py
Normal file
262
TestPrograms/test_harness.py
Normal file
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
from typing import Any, Dict, Optional
|
||||
from dataclasses import dataclass
|
||||
import time
|
||||
|
||||
# FastAPI TestClient for local calls without a real web server
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
# Import your classes from the main code (ensure this file is next to gitea_to_github_sync.py)
|
||||
from gitea_to_github_sync import PRAutocloserServer
|
||||
|
||||
# ---------------------------
|
||||
# In-memory fakes and helpers
|
||||
# ---------------------------
|
||||
|
||||
class InMemoryState:
|
||||
def __init__(self):
|
||||
self.map: Dict[str, int] = {}
|
||||
|
||||
def set_pr_bug(self, pr_key: str, bug_id: int):
|
||||
self.map[pr_key] = bug_id
|
||||
|
||||
def get_pr_bug(self, pr_key: str) -> Optional[int]:
|
||||
return self.map.get(pr_key)
|
||||
|
||||
@dataclass
|
||||
class RecordedComment:
|
||||
pr_number: int
|
||||
text: str
|
||||
|
||||
@dataclass
|
||||
class RecordedLabel:
|
||||
pr_number: int
|
||||
label: str
|
||||
|
||||
class FakeIssue:
|
||||
def __init__(self, pr_number: int, tracker: "FakeRepo"):
|
||||
self.pr_number = pr_number
|
||||
self.tracker = tracker
|
||||
|
||||
def add_to_labels(self, label: str):
|
||||
self.tracker.labels.append(RecordedLabel(self.pr_number, label))
|
||||
|
||||
class FakePR:
|
||||
def __init__(self, number: int, tracker: "FakeRepo"):
|
||||
self.number = number
|
||||
self.state = "open"
|
||||
self.tracker = tracker
|
||||
|
||||
def create_issue_comment(self, text: str):
|
||||
self.tracker.comments.append(RecordedComment(self.number, text))
|
||||
|
||||
def edit(self, state: str):
|
||||
if state in ("open", "closed"):
|
||||
self.state = state
|
||||
|
||||
def as_issue(self):
|
||||
return FakeIssue(self.number, self.tracker)
|
||||
|
||||
class FakeRepo:
|
||||
def __init__(self, full_name: str):
|
||||
self.full_name = full_name
|
||||
self._prs: Dict[int, FakePR] = {}
|
||||
self.comments: list[RecordedComment] = []
|
||||
self.labels: list[RecordedLabel] = []
|
||||
self.created_labels: set[str] = set()
|
||||
|
||||
def get_pull(self, number: int) -> FakePR:
|
||||
if number not in self._prs:
|
||||
self._prs[number] = FakePR(number, self)
|
||||
return self._prs[number]
|
||||
|
||||
def get_issue(self, number: int) -> FakeIssue:
|
||||
return FakeIssue(number, self)
|
||||
|
||||
def create_label(self, name: str, color: str):
|
||||
self.created_labels.add(name)
|
||||
|
||||
class FakeGhApi:
|
||||
def __init__(self, repo_full_name: str):
|
||||
self.repo_full_name = repo_full_name
|
||||
self.repo = FakeRepo(repo_full_name)
|
||||
|
||||
def get_repo(self, full_name: str) -> FakeRepo:
|
||||
assert full_name == self.repo_full_name, f"Unexpected repo requested: {full_name}"
|
||||
return self.repo
|
||||
|
||||
class FakeGitHubClient:
|
||||
def __init__(self, repo_full_name: str, token: str = "gh_test_token"):
|
||||
self.token = token
|
||||
self.gh = FakeGhApi(repo_full_name)
|
||||
|
||||
# Match PRAutocloserServer usage
|
||||
def close_pr_with_comment_and_label(self, repo, pr_number: int, comment: str, label: Optional[str] = None):
|
||||
pr = repo.get_pull(pr_number)
|
||||
pr.create_issue_comment(comment)
|
||||
if label:
|
||||
repo.create_label(label, "ededed")
|
||||
repo.get_issue(pr_number).add_to_labels(label)
|
||||
if pr.state != "closed":
|
||||
pr.edit(state="closed")
|
||||
|
||||
def comment_on_pr(self, repo, pr_number: int, comment: str, label: Optional[str] = None):
|
||||
pr = repo.get_pull(pr_number)
|
||||
pr.create_issue_comment(comment)
|
||||
if label:
|
||||
repo.create_label(label, "ededed")
|
||||
repo.get_issue(pr_number).add_to_labels(label)
|
||||
|
||||
class FakeBugzillaClient:
|
||||
def __init__(self, fail_create: bool = False):
|
||||
self.fail_create = fail_create
|
||||
self.created_bugs: list[int] = []
|
||||
self.attachments: list[tuple[int, str]] = [] # (bug_id, filename)
|
||||
self.comments: list[tuple[int, str]] = [] # (bug_id, text)
|
||||
self._next_id = 1000
|
||||
|
||||
def create_bug(self, summary: str, description: str, component: str, visibility_groups=None) -> int:
|
||||
if self.fail_create:
|
||||
raise RuntimeError("Simulated Bugzilla create failure")
|
||||
bug_id = self._next_id
|
||||
self._next_id += 1
|
||||
self.created_bugs.append(bug_id)
|
||||
return bug_id
|
||||
|
||||
def add_attachment(self, bug_id: int, file_name: str, content_type: str, summary: str, data_bytes: bytes):
|
||||
# No-op, just record
|
||||
self.attachments.append((bug_id, file_name))
|
||||
|
||||
def add_comment(self, bug_id: int, comment: str):
|
||||
self.comments.append((bug_id, comment))
|
||||
|
||||
# HMAC signature helper
|
||||
def sign(secret: str, body: bytes) -> str:
|
||||
return "sha256=" + hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||||
|
||||
# Sample GitHub PR payload (minimized to fields used by the endpoint)
|
||||
def sample_pr_payload(action="opened") -> Dict[str, Any]:
|
||||
return {
|
||||
"action": action,
|
||||
"repository": {
|
||||
"full_name": "Koozali-SME-Server/smeserver-manager",
|
||||
"owner": {"login": "Koozali-SME-Server"},
|
||||
"name": "smeserver-manager",
|
||||
},
|
||||
"pull_request": {
|
||||
"number": 42,
|
||||
"html_url": "https://github.com/Koozali-SME-Server/smeserver-manager/pull/42",
|
||||
"title": "Test PR: improve logging",
|
||||
"body": "Please review these changes.",
|
||||
"user": {"login": "octocat", "html_url": "https://github.com/octocat"},
|
||||
"base": {"ref": "master", "sha": "9f8e7d6cafebabe0000deadbeef0000000000000"},
|
||||
"head": {"ref": "feature/logs", "sha": "a1b2c3ddeeddbb0000deadbeef0000000000000", "repo": {"owner": {"login": "octocat"}}},
|
||||
"created_at": "2025-09-16T12:34:56Z",
|
||||
"labels": [{"name": "enhancement"}],
|
||||
},
|
||||
}
|
||||
|
||||
# ---------------------------
|
||||
# Test runner
|
||||
# ---------------------------
|
||||
|
||||
def run_tests():
|
||||
# Config for server (only the parts the endpoint uses)
|
||||
cfg = {
|
||||
"sync": {
|
||||
"gitea": {"base_url": "https://src.koozali.org", "org": "smeserver"},
|
||||
"github": {"webhook": {"secret": "test_secret"}},
|
||||
},
|
||||
"bugzilla": {
|
||||
"base_url": "https://bugs.koozali.org",
|
||||
"templates": {
|
||||
"pr_comment_success": "Bug {bug_id}: {bugzilla_base_url}/show_bug.cgi?id={bug_id}\nCanonical: {gitea_repo_url}\n",
|
||||
"pr_comment_failure": "Unable to create bug. Please file at {bugzilla_base_url} (Component: {repo})\nPR: {pr_url}\n",
|
||||
"bug_summary": "[GH PR #{pr_number}] {org}/{repo}: {pr_title}",
|
||||
"bug_body": "PR: {pr_url}\nNotes:\n{pr_body}\n",
|
||||
"bug_update_comment": "Update for PR #{pr_number}",
|
||||
"pr_sync_short_comment": "Updated bug {bug_id}: {bug_url}",
|
||||
},
|
||||
"attach_diff": False, # disable network to GitHub patch API during tests
|
||||
"failure_policy": {"close_pr_on_bugzilla_failure": False, "label_on_bugzilla_failure": "bugzilla-needed"},
|
||||
"component_template": "{repo}",
|
||||
},
|
||||
}
|
||||
|
||||
repo_full = "Koozali-SME-Server/smeserver-manager"
|
||||
|
||||
# Test 1: Success path (bug created, PR closed)
|
||||
print("\n=== Test 1: Success path ===")
|
||||
ghc = FakeGitHubClient(repo_full)
|
||||
bzc = FakeBugzillaClient(fail_create=False)
|
||||
state = InMemoryState()
|
||||
server = PRAutocloserServer(cfg, state, ghc, bzc)
|
||||
client = TestClient(server.app)
|
||||
|
||||
body = json.dumps(sample_pr_payload("opened")).encode("utf-8")
|
||||
headers = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sign(cfg["sync"]["github"]["webhook"]["secret"], body),
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp = client.post("/webhook/github", data=body, headers=headers)
|
||||
print("Response:", resp.status_code, resp.json())
|
||||
# Inspect effects
|
||||
repo = ghc.gh.repo
|
||||
print("Created bugs:", bzc.created_bugs)
|
||||
print("PR comments:", [c.text.strip() for c in repo.comments])
|
||||
print("PR state:", repo.get_pull(42).state)
|
||||
assert repo.get_pull(42).state == "closed", "PR should be closed on success"
|
||||
|
||||
# Test 2: Failure path (bugzilla create fails, PR left open, guidance comment posted)
|
||||
print("\n=== Test 2: Failure path ===")
|
||||
ghc2 = FakeGitHubClient(repo_full)
|
||||
bzc2 = FakeBugzillaClient(fail_create=True)
|
||||
state2 = InMemoryState()
|
||||
server2 = PRAutocloserServer(cfg, state2, ghc2, bzc2)
|
||||
client2 = TestClient(server2.app)
|
||||
|
||||
body2 = json.dumps(sample_pr_payload("opened")).encode("utf-8")
|
||||
headers2 = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sign(cfg["sync"]["github"]["webhook"]["secret"], body2),
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp2 = client2.post("/webhook/github", data=body2, headers=headers2)
|
||||
print("Response:", resp2.status_code, resp2.json())
|
||||
repo2 = ghc2.gh.repo
|
||||
print("Created bugs:", bzc2.created_bugs)
|
||||
print("PR comments:", [c.text.strip() for c in repo2.comments])
|
||||
print("PR labels:", [l.label for l in repo2.labels])
|
||||
print("PR state:", repo2.get_pull(42).state)
|
||||
assert repo2.get_pull(42).state == "open", "PR should remain open on bugzilla failure"
|
||||
|
||||
# Test 3: Synchronize event with existing bug (attachments disabled here)
|
||||
print("\n=== Test 3: Synchronize with existing bug ===")
|
||||
ghc3 = FakeGitHubClient(repo_full)
|
||||
bzc3 = FakeBugzillaClient(fail_create=False)
|
||||
state3 = InMemoryState()
|
||||
server3 = PRAutocloserServer(cfg, state3, ghc3, bzc3)
|
||||
client3 = TestClient(server3.app)
|
||||
|
||||
# Seed a bug mapping as if created earlier
|
||||
state3.set_pr_bug(f"{repo_full}#42", 2001)
|
||||
|
||||
body3 = json.dumps(sample_pr_payload("synchronize")).encode("utf-8")
|
||||
headers3 = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sign(cfg["sync"]["github"]["webhook"]["secret"], body3),
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp3 = client3.post("/webhook/github", data=body3, headers=headers3)
|
||||
print("Response:", resp3.status_code, resp3.json())
|
||||
repo3 = ghc3.gh.repo
|
||||
print("PR comments:", [c.text.strip() for c in repo3.comments])
|
||||
print("Bug attachments recorded:", bzc3.attachments)
|
||||
print("PR state:", repo3.get_pull(42).state)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_tests()
|
||||
158
TestPrograms/test_webhook_endpoint_standalone.py
Normal file
158
TestPrograms/test_webhook_endpoint_standalone.py
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
from typing import Optional, Dict, Any
|
||||
from dataclasses import dataclass
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
import webhook_endpoint as ws # your standalone endpoint module
|
||||
|
||||
# --------- Fakes ---------
|
||||
|
||||
@dataclass
|
||||
class RecordedComment:
|
||||
pr_number: int
|
||||
text: str
|
||||
|
||||
@dataclass
|
||||
class RecordedLabel:
|
||||
pr_number: int
|
||||
label: str
|
||||
|
||||
class FakeIssue:
|
||||
def __init__(self, pr_number: int, repo: "FakeRepo"):
|
||||
self.pr_number = pr_number
|
||||
self.repo = repo
|
||||
def add_to_labels(self, label: str):
|
||||
self.repo.labels.append(RecordedLabel(self.pr_number, label))
|
||||
|
||||
class FakePR:
|
||||
def __init__(self, number: int, repo: "FakeRepo"):
|
||||
self.number = number
|
||||
self.repo = repo
|
||||
self.state = "open"
|
||||
def create_issue_comment(self, text: str):
|
||||
self.repo.comments.append(RecordedComment(self.number, text))
|
||||
def edit(self, state: str):
|
||||
if state in ("open", "closed"):
|
||||
self.state = state
|
||||
|
||||
class FakeRepo:
|
||||
def __init__(self, full_name: str):
|
||||
self.full_name = full_name
|
||||
self._prs: Dict[int, FakePR] = {}
|
||||
self.comments: list[RecordedComment] = []
|
||||
self.labels: list[RecordedLabel] = []
|
||||
self.created_labels: set[str] = set()
|
||||
def get_pull(self, number: int) -> FakePR:
|
||||
self._prs.setdefault(number, FakePR(number, self))
|
||||
return self._prs[number]
|
||||
def get_issue(self, number: int) -> FakeIssue:
|
||||
return FakeIssue(number, self)
|
||||
def create_label(self, name: str, color: str):
|
||||
self.created_labels.add(name)
|
||||
|
||||
class FakeGhApi:
|
||||
def __init__(self, repo_full_name: str):
|
||||
self.repo_full_name = repo_full_name
|
||||
self.repo = FakeRepo(repo_full_name)
|
||||
def get_repo(self, full_name: str) -> FakeRepo:
|
||||
assert full_name == self.repo_full_name
|
||||
return self.repo
|
||||
|
||||
class FakeGhSingleton:
|
||||
def __init__(self, repo_full_name: str):
|
||||
self._api = FakeGhApi(repo_full_name)
|
||||
def get_repo(self, full_name: str):
|
||||
return self._api.get_repo(full_name)
|
||||
|
||||
class FakeBugzilla:
|
||||
def __init__(self, fail_create: bool = False):
|
||||
self.fail_create = fail_create
|
||||
self.created_bugs: list[int] = []
|
||||
self.attachments: list[tuple[int, str]] = []
|
||||
self._next = 1000
|
||||
def create_bug(self, summary: str, description: str, component: str) -> int:
|
||||
if self.fail_create:
|
||||
raise RuntimeError("Simulated Bugzilla create failure")
|
||||
bug_id = self._next; self._next += 1
|
||||
self.created_bugs.append(bug_id)
|
||||
return bug_id
|
||||
def add_attachment(self, bug_id: int, filename: str, summary: str, data_bytes: bytes):
|
||||
self.attachments.append((bug_id, filename))
|
||||
def add_comment(self, bug_id: int, comment: str):
|
||||
pass
|
||||
|
||||
class InMemoryState:
|
||||
def __init__(self):
|
||||
self.map: Dict[str, int] = {}
|
||||
def get_bug(self, pr_key: str) -> Optional[int]:
|
||||
return self.map.get(pr_key)
|
||||
def set_bug(self, pr_key: str, bug_id: int):
|
||||
self.map[pr_key] = bug_id
|
||||
|
||||
# --------- Helpers ---------
|
||||
|
||||
def sign(secret: str, body: bytes) -> str:
|
||||
return "sha256=" + hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||||
|
||||
def sample_payload(action="opened") -> Dict[str, Any]:
|
||||
return {
|
||||
"action": action,
|
||||
"repository": {
|
||||
"full_name": "Koozali-SME-Server/smeserver-manager",
|
||||
"owner": {"login": "Koozali-SME-Server"},
|
||||
"name": "smeserver-manager",
|
||||
},
|
||||
"pull_request": {
|
||||
"number": 42,
|
||||
"html_url": "https://github.com/Koozali-SME-Server/smeserver-manager/pull/42",
|
||||
"title": "Improve logging",
|
||||
"body": "Please review.",
|
||||
"user": {"login": "octocat", "html_url": "https://github.com/octocat"},
|
||||
"base": {"ref": "master", "sha": "9f8e7d6cafebabe0000deadbeef0000000000000"},
|
||||
"head": {"ref": "feature/logs", "sha": "a1b2c3ddeeddbb0000deadbeef0000000000000", "repo": {"owner": {"login": "octocat"}}},
|
||||
"created_at": "2025-09-16T12:34:56Z",
|
||||
"labels": [{"name": "enhancement"}],
|
||||
},
|
||||
}
|
||||
|
||||
def run_tests():
|
||||
# Inject fakes into the running module singletons
|
||||
ws.gh = FakeGhSingleton("Koozali-SME-Server/smeserver-manager")
|
||||
ws.bz = FakeBugzilla(fail_create=False)
|
||||
ws.state = InMemoryState()
|
||||
|
||||
client = TestClient(ws.app)
|
||||
secret = os.environ.get("WEBHOOK_SECRET", "test_secret") # must match your server config
|
||||
payload = sample_payload("opened")
|
||||
body = json.dumps(payload).encode("utf-8")
|
||||
headers = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sign(secret, body),
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp = client.post("/webhook/github", data=body, headers=headers)
|
||||
print("Opened response:", resp.status_code, resp.json())
|
||||
repo = ws.gh.get_repo("Koozali-SME-Server/smeserver-manager")
|
||||
print("Comments:", [c.text.strip() for c in repo.comments])
|
||||
print("PR state:", repo.get_pull(42).state)
|
||||
print("Created bugs:", ws.bz.created_bugs)
|
||||
|
||||
# Test synchronize on same PR (existing bug id used)
|
||||
ws.state.set_bug("Koozali-SME-Server/smeserver-manager#42", ws.bz.created_bugs[0])
|
||||
payload_sync = sample_payload("synchronize")
|
||||
body_sync = json.dumps(payload_sync).encode("utf-8")
|
||||
headers_sync = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sign(secret, body_sync),
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
resp2 = client.post("/webhook/github", data=body_sync, headers=headers_sync)
|
||||
print("Sync response:", resp2.status_code, resp2.json())
|
||||
print("Attachments recorded:", ws.bz.attachments)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
run_tests()
|
||||
45
TestPrograms/test_webhook_http.py
Normal file
45
TestPrograms/test_webhook_http.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
import os, json, hmac, hashlib, httpx
|
||||
|
||||
WEBHOOK_URL = os.environ.get("WEBHOOK_URL", "https://githubpr.bjsystems.co.uk/webhook/github")
|
||||
SECRET = os.environ.get("WEBHOOK_SECRET", "devsecret")
|
||||
|
||||
def sign(secret: str, body: bytes) -> str:
|
||||
return "sha256=" + hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||||
|
||||
def payload(action="opened"):
|
||||
return {
|
||||
"action": action,
|
||||
"repository": {
|
||||
"full_name": "Koozali-SME-Server/smeserver-manager",
|
||||
"owner": {"login": "Koozali-SME-Server"},
|
||||
"name": "smeserver-manager",
|
||||
},
|
||||
"pull_request": {
|
||||
"number": 52,
|
||||
"html_url": "https://github.com/Koozali-SME-Server/smeserver-manager/pull/42",
|
||||
"title": "Test PR from harness",
|
||||
"body": "Harness test body.",
|
||||
"user": {"login": "octocat", "html_url": "https://github.com/octocat"},
|
||||
"base": {"ref": "master", "sha": "9f8e7d6cafebabe0000deadbeef0000000000000"},
|
||||
"head": {"ref": "feature/test", "sha": "a1b2c3ddeeddbb0000deadbeef0000000000000", "repo": {"owner": {"login": "octocat"}}},
|
||||
"created_at": "2025-09-17T12:34:56Z",
|
||||
"labels": [{"name": "enhancement"}],
|
||||
},
|
||||
}
|
||||
|
||||
def post_event(action="opened"):
|
||||
body = json.dumps(payload(action)).encode("utf-8")
|
||||
headers = {
|
||||
"X-GitHub-Event": "pull_request",
|
||||
"X-Hub-Signature-256": sign(SECRET, body),
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
r = httpx.post(WEBHOOK_URL, data=body, headers=headers, timeout=30)
|
||||
print(f"{action} ->", r.status_code, r.text)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Send an "opened" event then a "synchronize" event
|
||||
post_event("opened")
|
||||
post_event("synchronize")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
74
changelog
Executable file
74
changelog
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
#echo $1
|
||||
#exit 0
|
||||
|
||||
|
||||
LANG="en_us_8859_1";
|
||||
dateJ=`date "+%Y-%m-%d"`;
|
||||
dateH=`date "+%a %b %d %Y"`;
|
||||
|
||||
|
||||
if [[ $1 ]] && [ ${1##*.} == "spec" ]
|
||||
then
|
||||
specfile=$1
|
||||
else
|
||||
specfile=`grep '\.spec' ./CVS/Entries|cut -d'/' -f2`
|
||||
fi
|
||||
|
||||
echo "search for release in $specfile";
|
||||
# could be
|
||||
#%define main_release 12.6
|
||||
#%define release 2
|
||||
#%define release 2%{?dist}
|
||||
#Release: 24
|
||||
#Release: 24%{?dist}
|
||||
rele=0;
|
||||
release=`cat $specfile|egrep '^%define (main_)?release'|cut -d " " -f3|cut -d% -f1`;
|
||||
if [[ ! $release ]]; then
|
||||
release=`cat $specfile|egrep '^Release:'|cut -d ":" -f2| tr -d "[:space:]"|cut -d% -f1`;
|
||||
rele=1;
|
||||
fi
|
||||
|
||||
echo "search for version in $specfile";
|
||||
#%define version 23
|
||||
#Version: 23
|
||||
version=`cat $specfile|grep -i '%define version'|cut -d " " -f3|cut -d% -f1`;
|
||||
if [[ ! $version ]]; then
|
||||
version=`cat $specfile|egrep '^Version:'|cut -d ":" -f2| tr -d "[:space:]"`;
|
||||
fi
|
||||
|
||||
|
||||
|
||||
echo "update release";
|
||||
oldrelease=$release;
|
||||
#release=$(($release + 1));# do not handle float
|
||||
#release=`echo "$release + 1"|bc`; # not always available
|
||||
addme=1;
|
||||
if [[ "$release" =~ ^[0-9]+\.[0-9]+$ ]]
|
||||
then
|
||||
addme=0.1;
|
||||
fi
|
||||
release=`lua -e "print( $release + $addme)"`;
|
||||
echo "update release $oldrelease ==> $release";
|
||||
if [ "$rele" -eq "0" ]; then
|
||||
cat $specfile |sed -r "s/(^%define (main_)?release) *$oldrelease/\1 $release/">$specfile.tmp;
|
||||
else
|
||||
cat $specfile |sed -r "s/(^Release:) *$oldrelease/\1 $release/">$specfile.tmp;
|
||||
fi
|
||||
cat $specfile.tmp > $specfile;
|
||||
|
||||
echo "updating changelog $specfile";
|
||||
entete="* $dateH Brian Read <brianr@bjsystems.co.uk> $version-$release.sme"
|
||||
changelog="- fix [SME: ]"
|
||||
cat $specfile |sed "/^%changelog/a $entete\n$changelog\n" >$specfile.tmp;
|
||||
cat $specfile.tmp>$specfile;
|
||||
rm -f $specfile.tmp
|
||||
echo "nano $specfile"
|
||||
# and check for old directory
|
||||
if [ -d "*.old" ]; then
|
||||
echo "old found"
|
||||
else
|
||||
echo "***Remember to make the old directory!!***"
|
||||
fi
|
||||
15
config
Normal file
15
config
Normal file
@@ -0,0 +1,15 @@
|
||||
[smegit]
|
||||
DEBUG=false
|
||||
# if first character ~ will be relative to users home, otherwise absolute
|
||||
WORKDIR=~/smegit
|
||||
COMMONREPO=https://src.koozali.org/smeserver/common.git
|
||||
# OpenAI key for readme comment lookup.
|
||||
OPENAI_API_KEY=<key - ask Brian for his..>
|
||||
[local]
|
||||
USER=<local GITEA user name>
|
||||
GITEAHOST=<local GITEA URL>
|
||||
GITEAACCESSTOKEN=<access token for local GITEA>
|
||||
[remote]
|
||||
USER=<remote GITEA user name>
|
||||
GITEAHOST=https://src.koozali.org
|
||||
GITEAACCESSTOKEN=<access token for https://src.koozali.org GITEA>
|
||||
339
git-cvs2git.sh
339
git-cvs2git.sh
@@ -2,32 +2,33 @@
|
||||
#
|
||||
# $1 = Module name e.g. smeserver-ddclient
|
||||
# $2 = Organisation (smeserver or smecontrib)e
|
||||
# $3 = "local" will use parameters set for local repository else it will use remote
|
||||
# optional (can be in any order)
|
||||
# <local> will use parameters set for local repository else it will use remote
|
||||
# <debug> turn on debug regardless of ~/.smegit/config
|
||||
# <noisy> print a line showing how it was called
|
||||
# This works whether the repo and local files exist of not (it deletes them if necessary)
|
||||
# However if the remote repo exists, it preserves the README.md file so that edits are not lost
|
||||
# Also note: I have had difficulty deleting all the link files in the source tree!
|
||||
#
|
||||
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "************git_cvs2git.sh <modulename> <organization> [<local>]"
|
||||
echo "************git-cvs2git.sh <modulename> <organization> [<local>]"
|
||||
exit 0
|
||||
fi
|
||||
clear
|
||||
echo "**************************************************************************************************"
|
||||
echo "* *"
|
||||
echo "* SMEServer - git_cvs2git $1 $2 $3 `date` *"
|
||||
echo "* *"
|
||||
echo "**************************************************************************************************"
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
#inifilename=$(find ~/GITFiles -name cvs2git.ini 2>/dev/null | head -n 1)
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here
|
||||
echo "ERROR*******No ini file found $inifilename"
|
||||
exit 1
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git-cvs2git.sh <modulename> <organization> [<local>]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
@@ -44,32 +45,57 @@ while read -r line || [[ -n "$line" ]]; do
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
DEBUG=false
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
NOISY=
|
||||
EXTRAPARAMS=
|
||||
for param in $3 $4 $5 $6; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
GITEAUser=${local_USER}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
noisy )
|
||||
NOISY=true ;;
|
||||
* )
|
||||
EXTRAPARAMS=$EXTRAPARAMS" "$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $NOISY ] ; then echo "git-cvs2git.sh $1 $2 $3 $4 $5 $6" ; fi
|
||||
if [ $DEBUG ] ; then echo "************found ini file: $inifilename" ; fi
|
||||
# Make this null if you want lots of output. Still quite a bit anyway
|
||||
QUIET="-q"
|
||||
curlsilent="-s"
|
||||
SILENT4CURL="-s"
|
||||
SILENT4MAKE="-s"
|
||||
if [ $DEBUG ] ; then
|
||||
QUIET=
|
||||
curlsilent=
|
||||
SILENT4CURL="-v"
|
||||
SILENT4MAKE=
|
||||
fi
|
||||
# Make this null to get curl to check ssl cert
|
||||
checkSSL="-k"
|
||||
|
||||
LOCALUser=${local_USER}
|
||||
WORKDIR=$(echo ~)/${smegit_WORKDIR}
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
if [ $3 ] ; then
|
||||
if [ $3 == "local" ] ; then
|
||||
GITEAUser=${local_USER}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
fi
|
||||
if [[ $smegit_WORKDIR == ~* ]] ; then
|
||||
# relative to users home dir
|
||||
WORKDIR=$(echo ~)${smegit_WORKDIR:1}
|
||||
else
|
||||
# absolute path
|
||||
WORKDIR=${smegit_WORKDIR}
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "WORKDIR=$WORKDIR" ; fi
|
||||
RemoteRepoURL="$GITEAHOST/$2/$1"
|
||||
|
||||
#
|
||||
@@ -83,10 +109,24 @@ COMMONREPO=${smegit_COMMONREPO}
|
||||
# Name is re-initialised later on from the spec file
|
||||
NAME=$1
|
||||
|
||||
cd $WORKDIR
|
||||
CVSFiles="$WORKDIR/$2/rpms"
|
||||
#echo $CVSFiles
|
||||
mkdir -p $CVSFiles
|
||||
# Prepare variable for file in repo to indicate core or contrib.
|
||||
# and init gitea organisation
|
||||
# Adjust where we put the repo locally accordingly.
|
||||
ORGGITEA=$2
|
||||
if [[ "$2" == "smecontribs" ]]; then
|
||||
BASEORCONTRIB="contribs10"
|
||||
PRODUCTBUGZILLA="SME%20Contribs"
|
||||
else
|
||||
BASEORCONTRIB="sme10"
|
||||
PRODUCTBUGZILLA="SME%20Server%2010.X"
|
||||
fi
|
||||
|
||||
# Work out if it is an SMEServer package or a 3rd party one
|
||||
if [[ "$NAME" =~ ^(smeserver-|e-smith-).* ]]; then
|
||||
PACKAGETYPE="SMEServer Koozali developed"
|
||||
else
|
||||
PACKAGETYPE="3rd Party (Maintained by Koozali)"
|
||||
fi
|
||||
|
||||
# Check that git-lfs is installed
|
||||
if command -v git-lfs > /dev/null; then
|
||||
@@ -104,12 +144,23 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Check that lua is installed (needed for change-log)
|
||||
if command -v lua -V > /dev/null; then
|
||||
if [ $DEBUG ] ; then echo "************lua is installed" ; fi
|
||||
else
|
||||
echo "ERROR********************** lua is not installed (try EPEL)**************"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# and check for the special scripts - changelog and BogusDateBot.sh - I think these are available in the
|
||||
# mockbuild rpm, but beware Bug:12340 - changelog needs an edit to work!
|
||||
if type -P change-log >/dev/null 2>&1; then
|
||||
if [ $DEBUG ] ; then echo "************change-log is installed" ; fi
|
||||
else
|
||||
echo "ERROR********************change-log is not installed*********** (try installing smeserver-mockbuild)"
|
||||
exit 1
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "************..and also note bug:12340" ; fi
|
||||
|
||||
@@ -117,11 +168,18 @@ if type -P BogusDateBot.sh >/dev/null 2>&1; then
|
||||
if [ $DEBUG ] ; then echo "************BogusDateBot.sh is installed"; fi
|
||||
else
|
||||
echo "ERROR********************BogusDateBot.sh is not installed*********** (try installing smeserver-mockbuild)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create work directories
|
||||
cd $WORKDIR
|
||||
CVSFiles="$WORKDIR/$2/rpms"
|
||||
#echo $CVSFiles
|
||||
mkdir -p $CVSFiles
|
||||
|
||||
# Make sure credentials taken from store
|
||||
# The first time you pull or push it will ask for credentials and then save them in a file.
|
||||
git config --global credential.helper store
|
||||
git config --global credential.helper store
|
||||
|
||||
#
|
||||
# Clone the CVS repository
|
||||
@@ -130,35 +188,13 @@ cd $CVSFiles
|
||||
# First delete any existing module directory tree
|
||||
# if there at all
|
||||
if [ -d "$1" ] ; then
|
||||
if [ $DEBUG ] ; then echo "************Deleting local CVS files" ; fi
|
||||
cd $CVSFiles/$1
|
||||
# Delete all files, links and directories
|
||||
find . -maxdepth 999 -xtype l -delete
|
||||
find . -maxdepth 999 -type f -delete
|
||||
# we seem to need this as well
|
||||
find . -xtype l -exec rm -f {} +
|
||||
find . -maxdepth 999 -type d -delete
|
||||
cd $CVSFiles
|
||||
# rm -Rf $1
|
||||
if [ $DEBUG ] ; then echo "************Deleting local CVS files" ; fi
|
||||
rm -Rf $CVSFiles/$1
|
||||
fi
|
||||
|
||||
|
||||
# Then get it fully from CVS
|
||||
cd $CVSFiles
|
||||
cvs -d:ext:shell.koozali.org:/cvs/$2 $QUIET checkout $1
|
||||
|
||||
# Prepare variable for file in repo to indicate core or contrib.
|
||||
# and init gitea organisation
|
||||
# Adjust where we put the repo locally accordingly.
|
||||
ORGGITEA=$2
|
||||
if [ "$2" == "smecontribs" ]; then
|
||||
BASEORCONTRIB="contribs10"
|
||||
PRODUCTBUGZILLA="SME%20Contribs"
|
||||
else
|
||||
BASEORCONTRIB="sme10"
|
||||
PRODUCTBUGZILLA="SME%20Server%2010.X"
|
||||
fi
|
||||
|
||||
cvs -d:ext:shell.koozali.org:/cvs/$2 $QUIET checkout $1
|
||||
|
||||
# Check that the spec file is there
|
||||
# First bet is the packagename.spec
|
||||
@@ -201,101 +237,62 @@ if [[ $GOTONE -eq 0 ]] ; then
|
||||
fi
|
||||
|
||||
# Create the local Git repository
|
||||
GITFiles=$WORKDIR/GITFiles/$ORGGITEA
|
||||
GITFiles=$WORKDIR/$ORGGITEA
|
||||
mkdir -p $GITFiles
|
||||
cd $GITFiles
|
||||
|
||||
# Delete the local first
|
||||
if [ -d "$1" ] ; then
|
||||
if [ $DEBUG ] ; then echo "************Deleting local GIT files" ; fi
|
||||
cd $GITFiles/$1
|
||||
find . -maxdepth 999 -xtype l -delete
|
||||
find . -maxdepth 999 -type f -delete
|
||||
# we seem to need this as well
|
||||
find . -xtype l -exec rm -f {} +
|
||||
find . -maxdepth 999 -type d -delete
|
||||
cd $GITFiles
|
||||
rmdir $1
|
||||
# rm -Rf $1
|
||||
rm -Rf $GITFiles/$1
|
||||
fi
|
||||
|
||||
|
||||
# See if it exists on the Gitea host
|
||||
REPO_NAME=$1
|
||||
RESPONSE=$(curl "$checkSSL" -s -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORGGITEA/$REPO_NAME")
|
||||
if [ $DEBUG ] ; then echo "check that $GITEAHOST/$ORGGITEA/$REPO_NAME exists" ; fi
|
||||
READMECONTENTS=
|
||||
RESPONSE=$(curl $checkSSL $SILENT4CURL -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORGGITEA/$REPO_NAME")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
if [ $DEBUG ] ; then echo "************Repository for $1 already exists!" ; fi
|
||||
# If so, clone it (just want the README.md)
|
||||
# And Clone it
|
||||
if [ $DEBUG ] ; then echo "git clone $GITEAHOST/$ORGGITEA/$1.git" ; fi
|
||||
cd $GITFiles
|
||||
git clone "$GITEAHOST/$ORGGITEA/$1.git"
|
||||
#GIT_SSL_NO_VERIFY=true git clone "$GITEAHOST/$ORGGITEA/$1.git"
|
||||
NOREPO=0
|
||||
else
|
||||
if [ $DEBUG ] ; then echo "************Repository for $1 does not exist." ; fi
|
||||
NOREPO=1
|
||||
fi
|
||||
|
||||
# then pull in the README
|
||||
READMECONTENTS="";
|
||||
cd $GITFiles
|
||||
if [ -d "$1" ] ; then
|
||||
cd $GITFiles/$1
|
||||
# Retain the contents of the README.md (incase its been editted, and saving multiple GPT accesses)
|
||||
if [ -f README.md ]; then
|
||||
git clone "$GITEAHOST/$ORGGITEA/$1.git"
|
||||
if [[ -f $GITFILES/$1/README.md ]] ; then
|
||||
# Move it and remember its new (temp) name
|
||||
READMECONTENTS=`mktemp`
|
||||
mv -f README.md "$READMECONTENTS"
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "************Saved README: $READMECONTENTS" ; fi
|
||||
cd $GITFiles
|
||||
# Now delete the repo, re-create it and clone it in to local
|
||||
if [ $DEBUG ] ; then echo "Delete $ORGGITEA/$1" ; fi
|
||||
RESPONSE=$(curl "$checkSSL" "$SILENT4CURL" -o /dev/null -w "%{http_code}" -X 'DELETE' \
|
||||
"$GITEAHOST/api/v1/repos/$ORGGITEA/$1" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN")
|
||||
if [[ $RESPONSE == "204" || $RESPONSE == "404" ]] ; then
|
||||
if [ $DEBUG ] ; then echo "************Repository $ORGGITEA/$1 deleted or does not exist" ; fi
|
||||
else
|
||||
echo "************Can NOT delete Repository $ORGGITEA/$1 - results will be unknown - Aborting!"
|
||||
echo "RESPONSE=$RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
# Delete all files, links and directories
|
||||
if [ $DEBUG ] ; then echo "************Deleting local GIT files" ; fi
|
||||
find . -maxdepth 999 -xtype l -delete
|
||||
find . -maxdepth 999 -type f -delete
|
||||
# we seem to need this as well
|
||||
find . -xtype l -exec rm -f {} +
|
||||
find . -maxdepth 999 -type d -delete
|
||||
cd $GITFiles
|
||||
rmdir $1
|
||||
# rm -Rf $1
|
||||
rm -Rf $GITFiles/$1
|
||||
else
|
||||
if [ $DEBUG ] ; then echo "************Repository for $1 does not exist." ; fi
|
||||
fi
|
||||
|
||||
|
||||
cd $GITFiles
|
||||
#git init $QUIET $1
|
||||
|
||||
# Now delete the remote repo and re-create it and clone it in to local
|
||||
curl "$checkSSL" "$curlsilent" -X 'DELETE' \
|
||||
"$GITEAHOST/api/v1/repos/$ORGGITEA/$1" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN"
|
||||
|
||||
# and check if it is here.
|
||||
RESPONSE=$(curl $curlsilent -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORGGITEA/$1")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
if [ $DEBUG ] ; then echo "************Repository for $1 exists!" ; fi
|
||||
GOTREPO=0
|
||||
else
|
||||
if [ $DEBUG ] ; then echo "************Repository for $1 does not exist" ; fi
|
||||
GOTREPO=1
|
||||
fi
|
||||
|
||||
# Work out if it is an SMEServer package or a 3rd party one
|
||||
if [[ "$NAME" =~ ^(smeserver-|e-smith-).* ]]; then
|
||||
PACKAGETYPE="SMEServer Koozali developed"
|
||||
else
|
||||
PACKAGETYPE="3rd Party (Maintained by Koozali)"
|
||||
fi
|
||||
|
||||
#
|
||||
# Use the API interface to create the remote repo
|
||||
# Re-create the repo
|
||||
#
|
||||
if [ $DEBUG ] ; then echo "************Creating repo for $1 $PACKAGETYPE" ; fi
|
||||
|
||||
if [[ $GOTREPO -eq 1 ]] ; then
|
||||
#Create it if it does not exist
|
||||
JSONREPO=$(curl "$checkSSL" "$curlsilent" -X 'POST' "$GITEAHOST/api/v1/orgs/$ORGGITEA/repos" \
|
||||
RESPONSE=$(curl "$checkSSL" "$SILENT4CURL" -X 'POST' \
|
||||
"$GITEAHOST/api/v1/orgs/$ORGGITEA/repos" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
@@ -312,38 +309,31 @@ if [[ $GOTREPO -eq 1 ]] ; then
|
||||
"template": false,
|
||||
"trust_model": "Default Trust Model"
|
||||
}')
|
||||
|
||||
if [ $DEBUG ] ; then echo $JSONREPO ; fi
|
||||
if [ $DEBUG ] ; then echo $RESPONSE ; fi
|
||||
|
||||
# and extract the http URL for it
|
||||
HTTP_URL=`echo $JSONREPO | jq -r '.html_url'`
|
||||
# and extract the http URL for it
|
||||
HTTP_URL=`echo $RESPONSE | jq -r '.html_url'`
|
||||
|
||||
if [ $DEBUG ] ; then echo $HTTP_URL ; fi
|
||||
|
||||
if [[ -z "${HTTP_URL}" ]]; then
|
||||
echo "ERROR*******Repo for $1 appears NOT to have been created "
|
||||
echo "$JSONREQ"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Already there
|
||||
HTTP_URL=$RemoteRepoURL
|
||||
JSONREQ="$1 Already exists"
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo $HTTP_URL ; fi
|
||||
if [[ -z "${HTTP_URL}" ]]; then
|
||||
echo "ERROR*******Repo for $1 appears NOT to have been created "
|
||||
echo "$RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# And check it now exists
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORGGITEA/$1")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
RESPONSE=$(curl "$SILENT4CURL" -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORGGITEA/$1")
|
||||
if [[ "$RESPONSE" == "200" ]]; then
|
||||
if [ $DEBUG ] ; then echo "************Repository for $1 exists" ; fi
|
||||
else
|
||||
echo "ERROR*******Repository for $1 has not been created ($JSONREQ)"
|
||||
echo "ERROR*******Repository for $1 has not been created ($RESPONSE)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Pull in the auto created or updated files
|
||||
cd $GITFiles
|
||||
#GIT_SSL_NO_VERIFY=true git clone "$GITEAHOST/$ORGGITEA/$1.git"
|
||||
git clone "$GITEAHOST/$ORGGITEA/$1.git"
|
||||
git clone "$GITEAHOST/$ORGGITEA/$1.git"
|
||||
|
||||
if [ ! -d $GITFiles/$1 ] ; then
|
||||
echo "ERROR*******Unable to access the new repo directory for $HTTP_URL $GITFiles/$1"
|
||||
@@ -355,7 +345,8 @@ cd $CVSFiles/$1/$BASEORCONTRIB
|
||||
# Fully populate the directory (gets the tar file - which is not strictly in CVS) and creates the directory source tree
|
||||
# applying the patches to the base in the tar file.
|
||||
# Might need to replace this by the code from the makefile if we decide to move "make prep" to git moe likely we'll implement a new one "make gitprep".
|
||||
make prep
|
||||
make $SILENT4MAKE prep
|
||||
#echo `pwd`; exit 0
|
||||
|
||||
# Extract the directory name for the file tree (it will include the name of the module plus some version information)
|
||||
# Same trick that we use in the makefile.common - taking the name and verison from the .spec file.
|
||||
@@ -376,7 +367,7 @@ if [ ! -f $ARCHIVEFILE ]; then
|
||||
# Try another tack
|
||||
if [ $DEBUG ] ; then echo "************File $ARCHIVE does not exist - trying *.$EXT" ; fi
|
||||
ARCHIVEFILE=`ls *.$EXT | head -n 1`
|
||||
if [ ! -f $ARCHIVEFILE || -z $ARCHIVEFILE ]; then
|
||||
if [[ ! -f $ARCHIVEFILE || -z $ARCHIVEFILE ]]; then
|
||||
echo "ERROR*******Can't identify archive file $ARCHIVEFILE $EXT `pwd`"
|
||||
exit 1
|
||||
fi
|
||||
@@ -395,7 +386,7 @@ echo $BASEORCONTRIB > contriborbase
|
||||
BASESPECFILE=$(basename $SPECFILE)
|
||||
for fpath in "$BASESPECFILE" "Makefile"
|
||||
do
|
||||
echo "************Copying $CVSFiles/$1/$BASEORCONTRIB/$fpath"
|
||||
if [ $DEBUG ] ; then echo "************Copying $CVSFiles/$1/$BASEORCONTRIB/$fpath" ; fi
|
||||
if [[ -f $CVSFiles/$1/$BASEORCONTRIB/$fpath ]] ; then
|
||||
cp -R $CVSFiles/$1/$BASEORCONTRIB/$fpath .
|
||||
else
|
||||
@@ -498,7 +489,7 @@ done
|
||||
echo "*.rpm" >> .gitignore
|
||||
echo "*.log" >> .gitignore
|
||||
# and the backed up spec file from BogusDateBot.sh
|
||||
echo "*spec-2023*" >>.gitignore
|
||||
echo "*spec-20*" >>.gitignore
|
||||
|
||||
cd $GITFiles/$1
|
||||
# See if the package is a 3rd party or one of ours - indicated by "smeserver" or "e-smith" in the name
|
||||
@@ -510,12 +501,12 @@ if [[ "$NAME" =~ ^(smeserver-|e-smith-).* ]]; then
|
||||
#and copy in the source tree
|
||||
mkdir -p "$CODEDIR"
|
||||
if [ $DEBUG ] ; then echo "************Copying $CVSFiles/$1/$BASEORCONTRIB/root `pwd`/$CODEDIR" ; fi
|
||||
rsync -a --no-prune-empty-dirs "$CVSFiles/$1/$BASEORCONTRIB/$TREEPATH/root/" "`pwd`/$CODEDIR/"
|
||||
rsync "$QUIET" -a --no-prune-empty-dirs "$CVSFiles/$1/$BASEORCONTRIB/$TREEPATH/root/" "`pwd`/$CODEDIR/"
|
||||
# copy createlinks to base
|
||||
if [ -e "$CVSFiles/$1/$BASEORCONTRIB/$TREEPATH/createlinks" ] ; then cp "$CVSFiles/$1/$BASEORCONTRIB/$TREEPATH/createlinks" "`pwd`/." ; fi
|
||||
# copy anything else in the base directory of $TREEPATH into the additional directory
|
||||
if [ ! -d "`pwd`/additional" ] ; then mkdir -p "`pwd`/additional" ; fi
|
||||
rsync -av --exclude "createlinks" --exclude "root/" "$CVSFiles/$1/$BASEORCONTRIB/$TREEPATH/" "`pwd`/additional/"
|
||||
rsync "$QUIET" -av --exclude "createlinks" --exclude "root/" "$CVSFiles/$1/$BASEORCONTRIB/$TREEPATH/" "`pwd`/additional/"
|
||||
# and plug a dummy into any empty directories
|
||||
find "`pwd`/root"/* -type d -empty -exec touch {}/.gitignore \;
|
||||
else
|
||||
@@ -536,24 +527,37 @@ else
|
||||
fi
|
||||
|
||||
cd $GITFiles/$1
|
||||
if [ $ARCHIVEFILE != "$TREEPATH.tar.gz" ] ; then
|
||||
echo "$ARCHIVEFILE" > archivefilename
|
||||
fi
|
||||
#if [[ $ARCHIVEFILE != "$TREEPATH.tar.gz" ]] ; then
|
||||
# echo "$ARCHIVEFILE" > archivefilename
|
||||
#fi
|
||||
|
||||
# Take out any bogus dates:
|
||||
/usr/bin/BogusDateBot.sh $(basename $SPECFILE)
|
||||
BogusDateBot.sh $(basename $SPECFILE)
|
||||
|
||||
# If it is an SME package, take out the patches and then update the release.
|
||||
if [[ "$NAME" =~ ^(smeserver-|e-smith-).* ]]; then
|
||||
# Now edit the spec file to remove all those patches and adjust the paths
|
||||
sed -i '/^Patch/d; /^%patch/d' $(basename $SPECFILE)
|
||||
# no paths need adjusting at this time!
|
||||
# - change Source: to new standard of tar.xz
|
||||
sed -i '/^Source:/s/tar.gz/tar.xz/;s/tgz/tar.xz/' $(basename $SPECFILE)
|
||||
# Bump the release and add changelog
|
||||
change-log $(basename $SPECFILE)
|
||||
# and edit in the reason
|
||||
# sed - TBD - to look for "fix [SME: ]"
|
||||
sed -i 's/fix \[SME: \]/Roll up patches and move to git repo \[SME: 12338\]/' $(basename $SPECFILE)
|
||||
sed -i 's/ME MYSELF <myemail@koozali.org>/cvs2git.sh aka Brian Read <brianr@koozali.org>/' $(basename $SPECFILE)
|
||||
# package specific changes needed because we use make prep to create the root tree
|
||||
if [[ $NAME == "e-smith-grub" ]] ; then
|
||||
sed -i '/^Source1:/d' $(basename $SPECFILE)
|
||||
sed -i '/^Source2:/d' $(basename $SPECFILE)
|
||||
sed -i '/^%setup/{n;N;N;N;d}' $(basename $SPECFILE)
|
||||
sed -i '/\[SME: 12338\]/a - Remove Source1 & Source2 \[SME: 12338\]' $(basename $SPECFILE)
|
||||
fi
|
||||
if [[ $NAME == "e-smith-lib" ]] ; then
|
||||
sed -i '/^%setup/{n;N;d}' $(basename $SPECFILE)
|
||||
sed -i '/\[SME: 12338\]/a - Remove create e-smith-lib-update event \[SME: 12338\]' $(basename $SPECFILE)
|
||||
fi
|
||||
# Add in the autochangelog and autorelease macros into the spec file
|
||||
# Commented out for now until we have build systems that can install the rpmautospec package (CEntos, Rocky etc V9 only so far)
|
||||
# sed -i 's/Release:.*/Release: %autorelease/' $(basename $SPECFILE)
|
||||
@@ -596,12 +600,9 @@ if [ ! -e $GITFiles/common ]; then
|
||||
else
|
||||
# Just refresh it
|
||||
cd $GITFiles/common
|
||||
git pull
|
||||
git pull $QUIET
|
||||
fi
|
||||
|
||||
# Now make sure that the make-archive is executible
|
||||
chmod +x $GITFiles/common/make-archive.sh
|
||||
|
||||
# Edit the Readme.md - try to add a link to the wiki for this package - only if it is an SME package
|
||||
cd $GITFiles/$1
|
||||
if [ $DEBUG ] ; then echo "************READMECONTENTS:$READMECONTENTS" ; fi
|
||||
@@ -638,7 +639,7 @@ if [[ "$NAME" =~ ^(smeserver-|e-smith-).* ]]; then
|
||||
if [[ ! "$URL" =~ 'fr' ]] ; then echo "${URL}"; break; fi \
|
||||
done <<< "${RESULTS}" )
|
||||
|
||||
if [ "$READMECONTENTS" == "" ]; then
|
||||
if [[ "$READMECONTENTS" == "" ]]; then
|
||||
# nothing previous
|
||||
# Copy across the Wiki links to the README
|
||||
if [ ! "$URLS" = "" ]; then
|
||||
@@ -668,14 +669,14 @@ if [[ "$NAME" =~ ^(smeserver-|e-smith-).* ]]; then
|
||||
model="text-davinci-003"
|
||||
temperature=0.8
|
||||
# Send the request to the API
|
||||
response=$(curl "$curlsilent" -X POST https://api.openai.com/v1/engines/$model/completions \
|
||||
response=$(curl "$SILENT4CURL" -X POST https://api.openai.com/v1/engines/$model/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
||||
-d '{"prompt": "'"$prompt"'", "temperature": 0.8, "max_tokens": 256}')
|
||||
# Extract the text from the response
|
||||
PARAGRAPH=`echo $response | jq -r '.choices[].text'`
|
||||
# Add it to what was there already
|
||||
echo "************Creating description for $1"
|
||||
if [ $DEBUG ] ; then echo "************Creating description for $1" ; fi
|
||||
echo -e "\n\n## Description\n" >> README.md
|
||||
echo -e "<br />*This description has been generated by an LLM AI system and cannot be relied on to be fully correct.*" >> README.md
|
||||
echo -e "*Once it has been checked, then this comment will be deleted*" >> README.md
|
||||
@@ -692,7 +693,7 @@ else
|
||||
model="text-davinci-003"
|
||||
temperature=0.8
|
||||
# Send the request to the API
|
||||
response=$(curl "$curlsilent" -X POST https://api.openai.com/v1/engines/$model/completions \
|
||||
response=$(curl "$SILENT4CURL" -X POST https://api.openai.com/v1/engines/$model/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $OPENAI_API_KEY" \
|
||||
-d '{"prompt": "'"$prompt"'", "temperature": 0.8, "max_tokens": 256}')
|
||||
@@ -717,7 +718,7 @@ if [[ -z $WIKILINK ]] ; then
|
||||
fi
|
||||
|
||||
# and then update the repo parameters
|
||||
RESPONSE=$(curl "$curlsilent" -X 'PATCH' "$GITEAHOST/api/v1/repos/$ORGGITEA/$REPO_NAME" \
|
||||
RESPONSE=$(curl "$SILENT4CURL" -X 'PATCH' "$GITEAHOST/api/v1/repos/$ORGGITEA/$REPO_NAME" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
@@ -741,23 +742,27 @@ cd $GITFiles/$1
|
||||
git add -A
|
||||
echo "$1 git status" >>gitstatus.log
|
||||
git status >>gitstatus.log
|
||||
git status
|
||||
if [ $DEBUG ] ; then git status ; fi
|
||||
COMMENT="initial commit of file from CVS for $1 on `date`"
|
||||
git commit -m "$COMMENT" $QUIET
|
||||
|
||||
# push the converted git repository to the remote
|
||||
git remote remove origin
|
||||
git remote remove origin
|
||||
git remote add origin "$GITEAHOST/$ORGGITEA/$1.git"
|
||||
#GIT_SSL_NO_VERIFY=true git push --force -u $QUIET origin master
|
||||
git push --force -u $QUIET origin master
|
||||
|
||||
# Now create the version and release tag for these files
|
||||
RELEASE=`rpm --queryformat '%{release}\n' --specfile $NAME.spec | head -n 1`
|
||||
TAG=$VERSION-$RELEASE
|
||||
VERSION_RELEASE_LONG=`rpm --queryformat '%{version} %{release}\n' --specfile $NAME.spec`
|
||||
VERSION_RELEASE=${VERSION_RELEASE_LONG%%$'\n'*}
|
||||
VERSION=${VERSION_RELEASE% *}
|
||||
VERSION=${VERSION//./_}
|
||||
RELEASE=${VERSION_RELEASE#* }
|
||||
# Release is not reliable - if you run on Rocky it comes back EL8, centos 7 - EL7
|
||||
# So, we need to just take the build part (first word)
|
||||
TAG=$VERSION"-"${RELEASE%.*}"_el8_sme"
|
||||
git tag -a $TAG -m "$COMMENT"
|
||||
git push origin $TAG
|
||||
git push origin $TAG $QUIET
|
||||
|
||||
echo "Created $1 Repo: $HTTP_URL - Comment:$COMMENT tag:$TAG"
|
||||
exit 0
|
||||
|
||||
|
||||
|
||||
84
git-delete-release-in-one-rep.sh
Executable file
84
git-delete-release-in-one-rep.sh
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# git-delete-release-in-one-rep.sh <organisation> <repo> [ <releasetag> | <id> ]
|
||||
#
|
||||
# Create the release (deleting one that is the same tag),
|
||||
# then uploads the .src.rpm and .rpm as an attachment (deleting any one of the same name)
|
||||
#
|
||||
#
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "git-delete-release-in-one-rep.sh <organisation> <repo> <organisation> <repo> [ <releasetag> | <id> ] [local] [debug]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git-delete-release-in-one-rep.sh <organisation> <repo> <organisation> <repo> [ <releasetag> | <id> ] [local] [debug]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
for param in $2 $3 $4 $5 $6 $7; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
GITEAUser=${local_USER}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
* )
|
||||
EXTRAPARAMS=$EXTRAPARAMS" "$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Uses if ist char is numeric to see if an id or tag is provided
|
||||
if [[ ! "${3:0:1}" =~ [0-9] ]]; then
|
||||
# <organisation> <repo> <releasetag> - find the id from the info provided
|
||||
ID=999;
|
||||
# TBD
|
||||
else
|
||||
ID=$3;
|
||||
fi
|
||||
|
||||
if [ $DEBUG ]; then echo "I:$ID"; fi
|
||||
|
||||
# And then delete it by id.
|
||||
RESPONSE=$(curl -s -X 'DELETE' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases/$ID" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN")
|
||||
if [ $DEBUG ]; then echo "$RESPONSE"; fi
|
||||
exit 0
|
||||
70
git-edit-readme.sh
Executable file
70
git-edit-readme.sh
Executable file
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# git-edit-readme.sh
|
||||
#
|
||||
# Edit the README.md for an smeserver package and alter the Bugzilla link
|
||||
#
|
||||
# $1 = package name
|
||||
|
||||
ORG=smecontribs # or smeserver
|
||||
|
||||
echo "$ORG / $1"
|
||||
|
||||
cd ~/GITFiles/$ORG
|
||||
if [ -d "$1" ]; then
|
||||
cd "$1"
|
||||
git pull
|
||||
else
|
||||
git clone "https://src.koozali.org/$ORG/$1"
|
||||
cd "$1"
|
||||
fi
|
||||
|
||||
echo "Current directory: `pwd`"
|
||||
|
||||
if [ -f "README.md" ]; then
|
||||
echo "Running awk to update README.md"
|
||||
|
||||
# Use a temporary file to handle multi-line replacement
|
||||
awk '/Show list of outstanding bugs: \[here\]/{
|
||||
print "Show list of outstanding bugs:"
|
||||
print "[All](https://bugs.koozali.org/buglist.cgi?action=wrap" \
|
||||
"&bug_status=UNCONFIRMED&bug_status=CONFIRMED" \
|
||||
"&bug_status=NEEDINFO&bug_status=IN_PROGRESS" \
|
||||
"&bug_status=RESOLVED&bug_status=VERIFIED" \
|
||||
"&classification=Contribs&component='"$1"'&list_id=105781" \
|
||||
"&order=changeddate+DESC%2Ccomponent%2Cpriority" \
|
||||
"%2Cbug_severity&product=SME+Contribs&query_format=advanced) "
|
||||
print "[Confirmed](https://bugs.koozali.org/buglist.cgi?action=wrap" \
|
||||
"&bug_status=CONFIRMED&classification=Contribs&component='"$1"'" \
|
||||
"&list_id=105781&order=changeddate+DESC%2Ccomponent%2Cpriority" \
|
||||
"%2Cbug_severity&product=SME+Contribs&query_format=advanced) "
|
||||
print "[Unconfirmed](https://bugs.koozali.org/buglist.cgi?action=wrap" \
|
||||
"&bug_status=UNCONFIRMED&classification=Contribs&component='"$1"'" \
|
||||
"&list_id=105781&order=changeddate+DESC%2Ccomponent%2Cpriority" \
|
||||
"%2Cbug_severity&product=SME+Contribs&query_format=advanced) "
|
||||
print "[Need Info](https://bugs.koozali.org/buglist.cgi?action=wrap" \
|
||||
"&bug_status=NEEDINFO&classification=Contribs&component='"$1"'" \
|
||||
"&list_id=105781&order=changeddate+DESC%2Ccomponent%2Cpriority" \
|
||||
"%2Cbug_severity&product=SME+Contribs&query_format=advanced) "
|
||||
print "[In Progress](https://bugs.koozali.org/buglist.cgi?action=wrap" \
|
||||
"&bug_status=IN_PROGRESS&classification=Contribs&component='"$1"'" \
|
||||
"&list_id=105781&order=changeddate+DESC%2Ccomponent%2Cpriority" \
|
||||
"%2Cbug_severity&product=SME+Contribs&query_format=advanced) "
|
||||
print "[Verified](https://bugs.koozali.org/buglist.cgi?action=wrap" \
|
||||
"&bug_status=VERIFIED&classification=Contribs&component='"$1"'" \
|
||||
"&list_id=105781&order=changeddate+DESC%2Ccomponent%2Cpriority" \
|
||||
"%2Cbug_severity&product=SME+Contribs&query_format=advanced) "
|
||||
print "[Resolved](https://bugs.koozali.org/buglist.cgi?action=wrap" \
|
||||
"&bug_status=RESOLVED&classification=Contribs&component='"$1"'" \
|
||||
"&list_id=105781&order=changeddate+DESC%2Ccomponent%2Cpriority" \
|
||||
"%2Cbug_severity&product=SME+Contribs&query_format=advanced) "
|
||||
next
|
||||
}1' README.md > README.tmp && mv README.tmp README.md
|
||||
|
||||
git status
|
||||
git add --all
|
||||
git commit -m "Update README with specific Bugzilla links"
|
||||
git push
|
||||
else
|
||||
echo "README.md not found in $1"
|
||||
fi
|
||||
57
git-get-latest-tag.sh
Executable file
57
git-get-latest-tag.sh
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "git-get-latest-tag.sh <modulename> <organisation>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git-cvs2git.sh <modulename> <organization> [<local>]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
|
||||
# Check that jq is installed
|
||||
if command -v jq -V > /dev/null; then
|
||||
if [ $DEBUG ] ; then echo "************Jq is installed" ; fi
|
||||
else
|
||||
echo "ERROR********************** jq is not installed (try EPEL)**************"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
|
||||
REPO_OWNER="$2"
|
||||
REPO_NAME="$1"
|
||||
|
||||
# Send request to Gitea API to get the list of tags
|
||||
LATEST_TAG=$(curl -H "Authorization: token $GITEAACCESSTOKEN" -s $GITEAHOST/api/v1/repos/$REPO_OWNER/$REPO_NAME/tags | jq -r '.[0].name')
|
||||
|
||||
# Print the latest tag
|
||||
echo "Latest tag for the repository $REPO_NAME is: $LATEST_TAG"
|
||||
@@ -4,12 +4,16 @@
|
||||
# monitor results and log
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ -z $inifilename ] ; then
|
||||
# Not here, look a bit further up
|
||||
echo "No ini file found $inifiename"
|
||||
echo "get-repo-and-build.sh <organisation> <reponame> [<local>]"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "get-repo-and-build.sh <organisation> <reponame> [branch=<branch> <local> <debug>]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
@@ -26,29 +30,54 @@ while read -r line || [[ -n "$line" ]]; do
|
||||
done < "$inifilename"
|
||||
|
||||
if [[ -z $1 && -z $2 ]] ; then
|
||||
echo "get-repo-and-build.sh <organisation> <reponame> [<local>]"
|
||||
echo "get-repo-and-build.sh <reponame> <organisation> [<local>]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
if [ $DEBUG ] ; then echo "found ini file: $inifilename" ; fi
|
||||
|
||||
curlsilent="-s"
|
||||
if [ $DEBUG ] ; then curlsilent= ; fi
|
||||
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
ACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
if [ $3 ] ; then
|
||||
if [ $3 == "local" ] ; then
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
ACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
fi
|
||||
ORG_NAME="$2"
|
||||
REPO_NAME="$1"
|
||||
BRANCH=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
for param in $3 $4 $5 $6; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
branch=* )
|
||||
BRANCH="--${param}"
|
||||
;;
|
||||
local )
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
ACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
* )
|
||||
TARGETORG=$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
SILENT="-s"
|
||||
QUIET="-q"
|
||||
if [ $DEBUG ] ; then
|
||||
echo "found ini file: $inifilename"
|
||||
SILENT=
|
||||
QUIET=
|
||||
fi
|
||||
ORG_NAME="$1"
|
||||
REPO_NAME="$2"
|
||||
WORKDIR=$(echo ~)${smegit_WORKDIR}
|
||||
GITFiles=$WORKDIR/GITFiles/$ORG_NAME
|
||||
|
||||
if [[ $smegit_WORKDIR == ~* ]] ; then
|
||||
# relative to users home dir
|
||||
WORKDIR=$(echo ~)${smegit_WORKDIR:1}
|
||||
else
|
||||
# absolute path
|
||||
WORKDIR=${smegit_WORKDIR}
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "WORKDIR=$WORKDIR" ; fi
|
||||
GITFiles=$WORKDIR/$ORG_NAME
|
||||
REPOURL="$GITEAHOST/$ORG_NAME/$REPO_NAME.git"
|
||||
|
||||
if [ $DEBUG ] ; then echo "getting $REPO_NAME from $ORG_NAME on $GITEAHOST" ; fi
|
||||
@@ -64,81 +93,82 @@ if [ $DEBUG ] ; then echo $GITFiles ; fi
|
||||
# See if it already exists
|
||||
if [ ! -e $GITFiles/common ]; then
|
||||
#Get it
|
||||
if [ $DEBUG ] ; then echo "clone common" ; fi
|
||||
cd $GITFiles
|
||||
git clone "${smegit_COMMONREPO}"
|
||||
git clone "${smegit_COMMONREPO}" $QUIET
|
||||
if [ ! -e $GITFiles/common ]; then
|
||||
echo "ERROR*******No Common Repo found - package $1"
|
||||
echo "ERROR*******No Common Repo found - package $REPO_NAME"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Just refresh it
|
||||
if [ $DEBUG ] ; then echo "refresh common" ; fi
|
||||
cd $GITFiles/common
|
||||
git pull
|
||||
fi
|
||||
|
||||
# Now make sure that the make-archive is executible
|
||||
chmod +x $GITFiles/common/make-archive.sh
|
||||
|
||||
# See if repo exits in git
|
||||
RESPONSE=$(curl $curlsilent -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORG_NAME/$REPO_NAME")
|
||||
if [ $DEBUG ] ; then echo "check if $REPO_NAME in $ORG_NAME exists on $GITEAHOST" ; fi
|
||||
BRANCHES=
|
||||
if [ $BRANCH ] ; then BRANCHES="/branches/${BRANCH#*=}" ; fi
|
||||
RESPONSE=$(curl $SILENT -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORG_NAME/$REPO_NAME$BRANCHES")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
echo "Repository for $1/$2 exists!"
|
||||
if [ $DEBUG ] ; then echo "Repository for $ORG_NAME/$REPO_NAME exists!" ; fi
|
||||
else
|
||||
echo "Repository for $1/$2 does not exist"
|
||||
logname="git-cvs2git-create-$2-$1-$(date +'%FT%H%M').log"
|
||||
while true; do
|
||||
read -p "Do you wish to run git-cvs2git?(y/n) " yn
|
||||
case $yn in
|
||||
[Yy]* ) git-cvs2git.sh "$REPO_NAME" "$ORG_NAME" > $logname; break;;
|
||||
[Nn]* ) exit;;
|
||||
* ) echo "Please answer yes or no.";;
|
||||
esac
|
||||
done
|
||||
if [ $DEBUG ] ; then echo "Repository for $ORG_NAME/$REPO_NAME does not exist" ; fi
|
||||
if [ $BRANCH ] ; then
|
||||
echo "Can't find the ${BRANCH#*=} branch of $ORG_NAME/$REPO_NAME - exiting"
|
||||
exit 1
|
||||
else
|
||||
while true; do
|
||||
read -p "Do you wish to run git-cvs2git?(y/n) " yn
|
||||
case $yn in
|
||||
[Yy]* )
|
||||
if [ $DEBUG ] ; then echo "running git-cvs2git.sh" ; fi
|
||||
logname="git-cvs2git-create-$ORG_NAME-$REPO_NAME-$(date +'%FT%H%M').log"
|
||||
git-cvs2git.sh "$REPO_NAME" "$ORG_NAME" > $logname
|
||||
break;;
|
||||
[Nn]* ) exit;;
|
||||
* ) echo "Please answer yes or no.";;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
# And check it is now there
|
||||
RESPONSE=$(curl $curlsilent -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORG_NAME/$REPO_NAME")
|
||||
if [ $DEBUG ] ; then echo "check if $REPO_NAME in $ORG_NAME exists on $GITEAHOST" ; fi
|
||||
RESPONSE=$(curl $SILENT -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORG_NAME/$REPO_NAME$BRANCHES")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
echo "Repository for $1/$2 created sucessfully!"
|
||||
if [ $DEBUG ] ; then echo "Repository for $ORG_NAME/$REPO_NAME created sucessfully!" ; fi
|
||||
else
|
||||
echo "git-cvs2git.sh was unable to create $1/$2 sucessfully"
|
||||
echo "git-cvs2git.sh was unable to create $ORG_NAME/$REPO_NAME sucessfully"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# Ok, we have a repo!!
|
||||
cd $GITFiles
|
||||
echo $GITFiles
|
||||
if [ $DEBUG ] ; then echo $GITFiles ; fi
|
||||
# Delete it if these already
|
||||
if [[ -d $REPO_NAME ]] ; then
|
||||
# Should delete everything....
|
||||
cd $GITFiles/$REPO_NAME
|
||||
echo "Deleting all files in $GITFiles/$REPO_NAME"
|
||||
rm -rf "$REPO_NAME"
|
||||
if [ $DEBUG ] ; then echo "Deleting all files in $GITFiles/$REPO_NAME" ; fi
|
||||
rm -rf "$GITFiles/$REPO_NAME"
|
||||
fi
|
||||
cd $GITFiles
|
||||
git clone "$REPOURL"
|
||||
|
||||
if [ $DEBUG ] ; then echo "cloning $REPOURL $BRANCH" ; fi
|
||||
git clone "$REPOURL" $BRANCH $QUIET
|
||||
|
||||
cd $GITFiles
|
||||
if [[ ! -d $REPO_NAME ]] ; then
|
||||
echo "git clone has not created the directory"
|
||||
if [[ ! -d $GITFiles/$REPO_NAME ]] ; then
|
||||
echo "git clone has not created the $REPO_NAME directory"
|
||||
exit 1
|
||||
fi
|
||||
cd $GITFiles/$REPO_NAME
|
||||
# and run mockbuild
|
||||
logname="mockbuild-$2-$1-$(date +'%FT%H%M').log"
|
||||
if [ $DEBUG ] ; then echo "running make mockbuild" ; fi
|
||||
logname="mockbuild-$ORG_NAME-$REPO_NAME-$(date +'%FT%H%M').log"
|
||||
if make mockbuild 2>&1 > $logname ; then
|
||||
echo "Looks like mockbuild worked"
|
||||
echo "$(date +'%FT%H%M') Mockbuild worked for $1/$2 " >> $GITFiles/mockbuilds.log
|
||||
echo "Looks like mockbuild worked for $ORG_NAME/$REPO_NAME"
|
||||
echo "$(date +'%FT%H%M') Mockbuild worked for $ORG_NAME/$REPO_NAME " >> $GITFiles/mockbuilds.log
|
||||
else
|
||||
echo "Mockbuild failed"
|
||||
echo "$(date +'%FT%H%M') Mockbuild failed for $1/$2 " >> $GITFiles/mockbuilds.log
|
||||
echo "$(date +'%FT%H%M') Mockbuild failed for $ORG_NAME/$REPO_NAME " >> $GITFiles/mockbuilds.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
494
git-getperl.sh
Executable file
494
git-getperl.sh
Executable file
@@ -0,0 +1,494 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# $1 = perl Module e.g. File::MMagic
|
||||
# $2 = Organisation (smeserver, smecontrib or user) - default smeserver
|
||||
# optional (can be in any order)
|
||||
# <local> will use parameters set for local repository else it will use remote
|
||||
# <debug> turn on debug regardless of ~/.smegit/config
|
||||
# <noisy> print a line showing how it was called
|
||||
# This works whether the repo and local files exist of not (it deletes them if necessary)
|
||||
# However if the remote repo exists, it preserves the README.md file so that edits are not lost
|
||||
# Also note: I have had difficulty deleting all the link files in the source tree!
|
||||
#
|
||||
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "************git-getperl.sh <modulename> <organization> [<local> | <debug> | <noisy>]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git-getperl.sh <modulename> <organization> [<local>]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
NOISY=
|
||||
EXTRAPARAMS=
|
||||
MODULENAME=$1
|
||||
ORGGITEA="smeserver"
|
||||
for param in $2 $3 $4 $5 $6; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
GITEAUser=${local_USER}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
noisy )
|
||||
NOISY=true ;;
|
||||
* )
|
||||
ORGGITEA=$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $NOISY ] ; then echo "git-getperl.sh $1 $2 $3 $4 $5 $6" ; fi
|
||||
if [ $DEBUG ] ; then echo "************found ini file: $inifilename" ; fi
|
||||
# Make this null if you want lots of output. Still quite a bit anyway
|
||||
QUIET="-q"
|
||||
SILENT4CURL="-s"
|
||||
SILENT4MAKE="-s"
|
||||
if [ $DEBUG ] ; then
|
||||
QUIET=
|
||||
SILENT4CURL="-v"
|
||||
SILENT4MAKE=
|
||||
fi
|
||||
# Make this null to get curl to check ssl cert
|
||||
checkSSL="-k"
|
||||
|
||||
LOCALUser=${local_USER}
|
||||
if [[ $smegit_WORKDIR == ~* ]] ; then
|
||||
# relative to users home dir
|
||||
WORKDIR=$(echo ~)${smegit_WORKDIR:1}
|
||||
else
|
||||
# absolute path
|
||||
WORKDIR=${smegit_WORKDIR}
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "WORKDIR=$WORKDIR" ; fi
|
||||
# create repo name from perl- module with :: replaced by -
|
||||
IFS=::
|
||||
words=()
|
||||
for i in $MODULENAME; do words+=($i) ; done
|
||||
RepoName="perl"
|
||||
ShortName=
|
||||
for word in ${words[@]}; do
|
||||
RepoName="$RepoName-$word"
|
||||
if [ $ShortName ] ; then
|
||||
ShortName="$ShortName-$word"
|
||||
else
|
||||
ShortName="$word"
|
||||
fi
|
||||
done
|
||||
if [ $DEBUG ] ; then echo "RepoName=$RepoName" ; fi
|
||||
IFS="${IFS:0:3}"
|
||||
RemoteRepoURL="$GITEAHOST/$ORGGITEA/$RepoName"
|
||||
|
||||
COMMONREPO=${smegit_COMMONREPO}
|
||||
|
||||
# Prepare variable for file in repo to indicate core or contrib.
|
||||
# and init gitea organisation
|
||||
# Adjust where we put the repo locally accordingly.
|
||||
ORGGITEA="smeserver"
|
||||
if [[ "$2" == "smecontribs" ]]; then
|
||||
ORGGITEA=$2
|
||||
BASEORCONTRIB="contribs10"
|
||||
PRODUCTBUGZILLA="SME%20Contribs"
|
||||
else
|
||||
BASEORCONTRIB="sme10"
|
||||
PRODUCTBUGZILLA="SME%20Server%2010.X"
|
||||
fi
|
||||
|
||||
# Work out if it is an SMEServer package or a 3rd party one
|
||||
PACKAGETYPE="3rd Party (Maintained by Koozali)"
|
||||
|
||||
# check that cpanspec is installed
|
||||
if command -v cpanspec >/dev/null; then
|
||||
if [ $DEBUG ] ; then echo "************cpanspec is installed"; fi
|
||||
else
|
||||
echo "ERROR********************cpanspec is not installed*********** (try installing cpanspec)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that git-lfs is installed
|
||||
if command -v git-lfs > /dev/null; then
|
||||
if [ $DEBUG ] ; then echo "************Git LFS is installed" ; fi
|
||||
else
|
||||
echo "ERROR********************** Git LFS is not installed ******************"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that lua is installed (needed for change-log)
|
||||
if command -v lua -V > /dev/null; then
|
||||
if [ $DEBUG ] ; then echo "************lua is installed" ; fi
|
||||
else
|
||||
echo "ERROR********************** lua is not installed (try EPEL)**************"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# and check for the special scripts - changelog and BogusDateBot.sh - I think these are available in the
|
||||
# mockbuild rpm, but beware Bug:12340 - changelog needs an edit to work!
|
||||
if type -P change-log >/dev/null 2>&1; then
|
||||
if [ $DEBUG ] ; then echo "************change-log is installed" ; fi
|
||||
else
|
||||
echo "ERROR********************change-log is not installed*********** (try installing smeserver-mockbuild)"
|
||||
exit 1
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "************..and also note bug:12340" ; fi
|
||||
|
||||
# Create work directories
|
||||
cd $WORKDIR
|
||||
perlFiles="$WORKDIR/$ORGGITEA/perl"
|
||||
mkdir -p $perlFiles
|
||||
|
||||
# Make sure credentials taken from store
|
||||
# The first time you pull or push it will ask for credentials and then save them in a file.
|
||||
git config --global credential.helper store
|
||||
|
||||
#
|
||||
# Create the perl repository
|
||||
#
|
||||
cd $perlFiles
|
||||
# First delete any existing module directory tree
|
||||
# if there at all
|
||||
if [ -d "$RepoName" ] ; then
|
||||
if [ $DEBUG ] ; then echo "************Deleting local CVS files" ; fi
|
||||
rm -Rf $perlFiles/$RepoName
|
||||
fi
|
||||
|
||||
# Then get it fully from CVS
|
||||
mkdir -p $perlFiles/$RepoName
|
||||
cd $perlFiles/$RepoName
|
||||
cpanspec "$MODULENAME"
|
||||
|
||||
# Check that the spec file is there
|
||||
# First bet is the packagename.spec
|
||||
SPECFILE=$RepoName.spec
|
||||
ORIGSPECFILE=$SPECFILE
|
||||
GOTONE=0
|
||||
if [ ! -f $SPECFILE ] ; then
|
||||
# See if it is a perl package which has the perl or perl-pear taken off the front
|
||||
for front in "perl-" "perl-pear-" ; do
|
||||
reg="^($front).*"
|
||||
echo "$front $RepoName $reg"
|
||||
if [[ "$RepoName" =~ $reg ]]; then
|
||||
NEWNAME="${RepoName#$front}"
|
||||
#echo $NEWNAME
|
||||
SPECFILE="$NEWNAME.spec"
|
||||
#echo $SPECFILE
|
||||
if [ -f $SPECFILE ] ; then
|
||||
GOTONE=1
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
GOTONE=1
|
||||
fi
|
||||
|
||||
if [[ $GOTONE -eq 0 ]] ; then
|
||||
echo "Cannot find .spec file: `pwd`/$ORIGSPECFILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the tarball file extension
|
||||
EXT=$(cat "$(basename $SPECFILE)" | grep -i ^Source | head -n 1 | sed -r 's/^[S|s]ource[0..9]?:\s?//' | xargs basename | sed -E 's/^([^.]*\.)(.*)$/\2/')
|
||||
|
||||
# Create the local Git repository
|
||||
GITFiles=$WORKDIR/$ORGGITEA
|
||||
mkdir -p $GITFiles
|
||||
cd $GITFiles
|
||||
|
||||
# Delete the local first
|
||||
if [ -d "$RepoName" ] ; then
|
||||
if [ $DEBUG ] ; then echo "************Deleting local GIT files" ; fi
|
||||
rm -Rf $GITFiles/$RepoName
|
||||
fi
|
||||
|
||||
# See if it exists on the Gitea host
|
||||
if [ $DEBUG ] ; then echo "check that $GITEAHOST/$ORGGITEA/$RepoName exists" ; fi
|
||||
RESPONSE=$(curl $checkSSL $SILENT4CURL -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORGGITEA/$RepoName")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
if [ $DEBUG ] ; then echo "************Repository for $RepoName already exists!" ; fi
|
||||
# Now delete the repo, re-create it and clone it in to local
|
||||
if [ $DEBUG ] ; then echo "Delete $ORGGITEA/$RepoName" ; fi
|
||||
RESPONSE=$(curl "$checkSSL" "$SILENT4CURL" -o /dev/null -w "%{http_code}" -X 'DELETE' \
|
||||
"$GITEAHOST/api/v1/repos/$ORGGITEA/$RepoName" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN")
|
||||
if [[ $RESPONSE == "204" || $RESPONSE == "404" ]] ; then
|
||||
if [ $DEBUG ] ; then echo "************Repository $ORGGITEA/$RepoName deleted or does not exist" ; fi
|
||||
else
|
||||
echo "************Can NOT delete Repository $ORGGITEA/$RepoName - results will be unknown - Aborting!"
|
||||
echo "RESPONSE=$RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
# Delete all files, links and directories
|
||||
if [ $DEBUG ] ; then echo "************Deleting local GIT files" ; fi
|
||||
cd $GITFiles
|
||||
rm -Rf $GITFiles/$RepoName
|
||||
else
|
||||
if [ $DEBUG ] ; then echo "************Repository for $RepoName does not exist." ; fi
|
||||
fi
|
||||
|
||||
cd $GITFiles
|
||||
|
||||
#
|
||||
# Re-create the repo
|
||||
#
|
||||
if [ $DEBUG ] ; then echo "************Creating repo for $RepoName $PACKAGETYPE" ; fi
|
||||
RESPONSE=$(curl "$checkSSL" "$SILENT4CURL" -X 'POST' \
|
||||
"$GITEAHOST/api/v1/orgs/$ORGGITEA/repos" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"auto_init": true,
|
||||
"default_branch": "master",
|
||||
"description": "'"$PACKAGETYPE git repo for $RepoName $ORGGITEA"'",
|
||||
"gitignores": "",
|
||||
"issue_labels": "Default",
|
||||
"license": "Apache-2.0",
|
||||
"name": "'"$RepoName"'",
|
||||
"private": false,
|
||||
"readme": "Default",
|
||||
"template": false,
|
||||
"trust_model": "Default Trust Model"
|
||||
}')
|
||||
if [ $DEBUG ] ; then echo $RESPONSE ; fi
|
||||
|
||||
# And check it now exists
|
||||
RESPONSE=$(curl "$SILENT4CURL" -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORGGITEA/$RepoName")
|
||||
if [[ "$RESPONSE" == "200" ]]; then
|
||||
if [ $DEBUG ] ; then echo "************Repository for $RepoName exists" ; fi
|
||||
else
|
||||
echo "ERROR*******Repository for $RepoName has not been created ($RESPONSE)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Tell repo to use koozali.org bugzilla and wiki - this does not work on CREATE currently - 19Apr2023
|
||||
WIKILINK="https://wiki.koozali.org/$RepoName"
|
||||
|
||||
# and then update the repo parameters
|
||||
RESPONSE=$(curl "$SILENT4CURL" -X 'PATCH' "$GITEAHOST/api/v1/repos/$ORGGITEA/$RepoName" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"external_tracker": {
|
||||
"external_tracker_format": "https://bugs.koozali.org/show_bug.cgi?id={index}",
|
||||
"external_tracker_style": "numeric",
|
||||
"external_tracker_url": "'"https://bugs.koozali.org/buglist.cgi?component=$RepoName&product=$PRODUCTBUGZILLA"'"
|
||||
},
|
||||
"external_wiki": {
|
||||
"external_wiki_url": "'"$WIKILINK"'"
|
||||
}
|
||||
}
|
||||
')
|
||||
# should check response here.
|
||||
if [ $DEBUG ] ; then echo $RESPONSE ; fi
|
||||
#exit 0
|
||||
|
||||
# Pull in the auto created or updated files
|
||||
cd $GITFiles
|
||||
git clone "$GITEAHOST/$ORGGITEA/$RepoName.git"
|
||||
|
||||
if [ ! -d $GITFiles/$RepoName ] ; then
|
||||
echo "ERROR*******Unable to access the new repo directory for $GITFiles/$RepoName"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fully populate the directory (gets the tar file - which is not strictly in CVS) and creates the directory source tree
|
||||
# applying the patches to the base in the tar file.
|
||||
# Might need to replace this by the code from the makefile if we decide to move "make prep" to git moe likely we'll implement a new one "make gitprep".
|
||||
cd $GITFiles/$RepoName
|
||||
cp $perlFiles/$RepoName/* .
|
||||
|
||||
# create the Makefile
|
||||
cat > Makefile <<- _EOT
|
||||
# Makefile for source rpm: $RepoName
|
||||
# \$Id: Makefile,v 1.1 2016/02/04 12:24:52 vip-ire Exp $
|
||||
NAME := $RepoName
|
||||
SPECFILE = \$(firstword \$(wildcard *.spec))
|
||||
|
||||
define find-makefile-common
|
||||
for d in common ../common ../../common ; do if [ -f \$\$d/Makefile.common ] ; then if [ -f \$\$d/CVS/Root -a -w \$\$/Makefile.common ] ; then cd \$\$d ; cvs -Q update ; fi ; echo "\$\$d/Makefile.common" ; break ; fi ; done
|
||||
endef
|
||||
|
||||
MAKEFILE_COMMON := \$(shell \$(find-makefile-common))
|
||||
|
||||
ifeq (\$(MAKEFILE_COMMON),)
|
||||
# attept a checkout
|
||||
define checkout-makefile-common
|
||||
test -f CVS/Root && { cvs -Q -d \$\$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2
|
||||
endef
|
||||
|
||||
MAKEFILE_COMMON := \$(shell \$(checkout-makefile-common))
|
||||
endif
|
||||
|
||||
include \$(MAKEFILE_COMMON)
|
||||
_EOT
|
||||
|
||||
# Add file indicating which release and contribs or base - this is matched by the makefile with the contents of the branch file in the common directory
|
||||
# to give the details of the release (EL7/8/9/ etc)
|
||||
# This assumes SME10 and contribs10 or sme10 directory names, later releases can update the value in the file and Makefile should still work.
|
||||
echo "sme11" > contriborbase
|
||||
|
||||
# and see if the spec file is not according to specification of <packagename>.spec
|
||||
# if not rename it
|
||||
if [[ $SPECFILE != $ORIGSPECFILE ]] ; then
|
||||
if [ $DEBUG ] ; then echo "************Renaming specfile from $(basename $SPECFILE) $(basename $ORIGSPECFILE)" ; fi
|
||||
mv "$(basename $SPECFILE)" "$(basename $ORIGSPECFILE)"
|
||||
SPECFILE=$ORIGSPECFILE
|
||||
fi
|
||||
|
||||
## and there may be extra files that maybe needed, these can be identified from the "Source" spec in the .spec files
|
||||
SOURCES=$(grep -i -E '^Source[0-9]*:' $(basename $SPECFILE) | cut -d: -f2- | sed 's/ //g')
|
||||
if [ $DEBUG ] ; then echo "$SOURCES" ; fi
|
||||
|
||||
#SOURCE=$(rpm --queryformat '$SOURCE\n' --specfile $SPECFILE | head -n 1)
|
||||
for fpath in $SOURCES; do
|
||||
# Needs another step incase the extraction from the spec file contains spec variables
|
||||
fpathfile=$(basename $fpath)
|
||||
if [ $DEBUG ] ; then echo "$fpathfile" ; fi
|
||||
translatefpath=$(rpm --queryformat "$fpathfile\n" --specfile $(basename $SPECFILE) | head -n 1)
|
||||
if [ $DEBUG ] ; then echo "$translatefpath" ; fi
|
||||
if [[ -f $perlFiles/$RepoName/$translatefpath ]] ; then
|
||||
if [ $DEBUG ] ; then echo "************Copying $perlFiles/$RepoName/$translatefpath" ; fi
|
||||
cp $perlFiles/$RepoName/$translatefpath .
|
||||
else
|
||||
if [ $DEBUG ] ; then echo "************Not found $perlFiles/$RepoName/$translatefpath ( $fpathfile )- so not copied" ; fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Take out the logs and rpms from the git save
|
||||
echo "*.rpm" >> .gitignore
|
||||
echo "*.log" >> .gitignore
|
||||
# and the backed up spec file from BogusDateBot.sh
|
||||
echo "*spec-20*" >>.gitignore
|
||||
|
||||
cd $GITFiles/$RepoName
|
||||
# All perl packages are Third party packages
|
||||
# copy over the archive file and make sure the extension is tracked by git-lfs
|
||||
if [ $DEBUG ] ; then echo "************Found 3rd party package $NAME" ; fi
|
||||
git lfs install
|
||||
git lfs track "*.$EXT"
|
||||
git add .gitattributes
|
||||
if [[ -f $perlFiles/$RepoName/$ARCHIVEFILE ]] ; then
|
||||
if [ $DEBUG ] ; then echo "************Copying archivefile $perlFiles/$RepoName/$ARCHIVEFILE" ; fi
|
||||
cp $perlFiles/$RepoName/$ARCHIVEFILE .
|
||||
else
|
||||
if [ $DEBUG ] ; then echo "Unable to find archivefile: $perlFiles/$RepoName/$ARCHIVEFILE - nothing copied" ; fi
|
||||
fi
|
||||
cd $GITFiles/$RepoName
|
||||
|
||||
# Add the BuildRequires now needed by el8(Rocky 8)
|
||||
sed -i -e '/BuildRequires/{a\BuildRequires: perl(inc::Module::Install)' -e ':a;n;ba}' "$SPECFILE"
|
||||
sed -i -e '/BuildRequires/{a\BuildRequires: perl(ExtUtils::Manifest)' -e ':a;n;ba}' "$SPECFILE"
|
||||
|
||||
# Re-factor the Common directory so that it is outside the repo being created.
|
||||
# one Common directory for each Organisation
|
||||
#
|
||||
# See if it already exists
|
||||
if [ ! -e $GITFiles/common ]; then
|
||||
#Get it
|
||||
cd $GITFiles
|
||||
git clone "${smegit_COMMONREPO}"
|
||||
if [ ! -e $GITFiles/common ]; then
|
||||
echo "ERROR*******No Common Repo found - package $RepoName"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Just refresh it
|
||||
cd $GITFiles/common
|
||||
git pull $QUIET
|
||||
fi
|
||||
|
||||
# Edit the Readme.md - try to add the description from the spec file for this package
|
||||
cd $GITFiles/$RepoName
|
||||
DESCRIPTION=`rpm --queryformat '%{description}\n' --specfile $SPECFILE`
|
||||
|
||||
# create the README.md
|
||||
cat > README.md <<- _EOT
|
||||
# $RepoName ($MODULENAME)
|
||||
|
||||
SMEServer Koozali local git repo for $RepoName
|
||||
|
||||
## Documentation
|
||||
https://metacpan.org/pod/$MODULENAME
|
||||
|
||||
## Bugs
|
||||
CPAN bug report are [here](https://rt.cpan.org/Public/Dist/Display.html?Name=$ShortName)
|
||||
|
||||
Show list of Koozali outstanding bugs: [here](https://bugs.koozali.org/buglist.cgi?component=$RepoName&product=SME%20Server%2011.X&query_format=advanced&limit=0&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=CONFIRMED)
|
||||
|
||||
## Description
|
||||
$DESCRIPTION
|
||||
_EOT
|
||||
|
||||
cd $GITFiles/$RepoName
|
||||
# stage and commit all the files created locally
|
||||
git add -A
|
||||
echo "$RepoName git status" >>gitstatus.log
|
||||
git status >>gitstatus.log
|
||||
if [ $DEBUG ] ; then git status ; fi
|
||||
COMMENT="initial create of smeserver perl $MODULENAME on `date`"
|
||||
git commit -m "$COMMENT" $QUIET
|
||||
|
||||
# push the converted git repository to the remote
|
||||
git remote remove origin
|
||||
git remote add origin "$GITEAHOST/$ORGGITEA/$RepoName.git"
|
||||
git push --force -u $QUIET origin master
|
||||
|
||||
# Now create the version and release tag from the specfile
|
||||
VERSION_RELEASE_LONG=`rpm --queryformat '%{version} %{release}\n' --specfile $SPECFILE`
|
||||
VERSION_RELEASE=${VERSION_RELEASE_LONG%%$'\n'*}
|
||||
VERSION=${VERSION_RELEASE% *}
|
||||
VERSION=${VERSION//./_}
|
||||
RELEASE=${VERSION_RELEASE#* }
|
||||
TAG=$VERSION"-"${RELEASE%.*}
|
||||
if [ $DEBUG ] ; then
|
||||
echo "VERSION_RELEASE=$VERSION_RELEASE"
|
||||
echo "VERSION=$VERSION"
|
||||
echo "RELEASE=$RELEASE"
|
||||
echo "TAG=$TAG"
|
||||
fi
|
||||
git pull
|
||||
git tag -a $TAG -m "align tag with version and release from spec file: $TAG"
|
||||
git push origin --tag $TAG $QUIET
|
||||
|
||||
|
||||
echo "$COMMENT tag:$TAG"
|
||||
exit 0
|
||||
148
git-list-all-org-repos.sh
Executable file
148
git-list-all-org-repos.sh
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
# Pull in parameters from a ini file
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifilename or /etc/smegit.ini"
|
||||
echo "git-list-all-org-repos.sh <organisation> [draftrelease | prerelease | release | allreleases] [cloneurl] [zipurl] [asseturls]"
|
||||
exit 1
|
||||
else
|
||||
inifilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
NOISY=
|
||||
EXTRAPARAMS=
|
||||
DEBUG=
|
||||
for param in $2 $3 $4 $5 $6 $7 $8 $9 $10; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
GITEAUser=${local_USER}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
noisy )
|
||||
NOISY=true ;;
|
||||
release )
|
||||
SHOWRELEASE=true;SHOWPRERELEASE=false;SHOWDRAFT=false ;;
|
||||
draftrelease )
|
||||
SHOWRELEASE=true;SHOWPRERELEASE=false;SHOWDRAFT=true ;;
|
||||
prerelease )
|
||||
SHOWRELEASE=true;SHOWPRERELEASE=true;SHOWDRAFT=false ;;
|
||||
allreleases )
|
||||
SHOWRELEASE=true;SHOWALLRELEASES=true ;;
|
||||
cloneurl )
|
||||
SHOWCLONEURL=true ;;
|
||||
zipurl )
|
||||
SHOWZIPURL=true ;;
|
||||
id )
|
||||
SHOWID=true ;;
|
||||
asseturls )
|
||||
SHOWASSETURLS=true ;;
|
||||
* )
|
||||
EXTRAPARAMS=$EXTRAPARAMS" "$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "git-list-all-org-repos.sh <organisation> [draftrelease | prerelease | release | allreleases] [cloneurl] [zipurl] [asseturls]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ORG_NAME="$1"
|
||||
PAGE_COUNTER=1
|
||||
REPO_LIST=""
|
||||
|
||||
while true; do
|
||||
REPO_PAGE=$(curl -s -H "Authorization: token $GITEAACCESSTOKEN" "$GITEAHOST/api/v1/orgs/$ORG_NAME/repos?page=$PAGE_COUNTER")
|
||||
if [[ $(echo $REPO_PAGE | jq length) -eq 0 ]]; then
|
||||
break
|
||||
fi
|
||||
REPO_LIST="$REPO_LIST $(echo $REPO_PAGE | jq -r .[].full_name | cut -d / -f 2 )"
|
||||
PAGE_COUNTER=$((PAGE_COUNTER+1))
|
||||
done
|
||||
REPO_LIST=$(echo $REPO_LIST | tr -s '[:space:]' '\n' | sort)
|
||||
for item in $REPO_LIST ; do
|
||||
line=$item
|
||||
if [[ $SHOWID || $SHOWRELEASE || $SHOWCLONEURL || $ZIPURL || $SHOWALLRELEASES ]] ; then
|
||||
#Find and show releases
|
||||
# echo "$GITEAHOST/api/v1/repos/$ORG_NAME/$item/releases?draft=true&pre-release=true&limit=100" \
|
||||
# -H 'accept: application/json' \
|
||||
# -H "Authorization: token $GITEAACCESSTOKEN"
|
||||
if [ $SHOWALLRELEASES ] ; then
|
||||
RESPONSE=$(curl -s -X 'GET' \
|
||||
"$GITEAHOST/api/v1/repos/$ORG_NAME/$item/releases" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN");
|
||||
else
|
||||
RESPONSE=$(curl -s -X 'GET' \
|
||||
"$GITEAHOST/api/v1/repos/$ORG_NAME/$item/releases?draft=$SHOWDRAFT&pre-release=$SHOWPRERELEASE&limit=100" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN");
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "$RESPONSE"; fi
|
||||
if [ $SHOWRELEASE ] ; then
|
||||
# Will need to use " jq 'map(.name)'" once we have more than one release.
|
||||
REL=$(echo $RESPONSE | jq -r '.[0].tag_name')
|
||||
ID=$(echo $RESPONSE | jq -r '.[0].id')
|
||||
PRE=$(echo $RESPONSE | jq -r '.[0].prerelease')
|
||||
DRAFT=$(echo $RESPONSE | jq -r '.[0].draft')
|
||||
# Get assets - json for any files uploaded
|
||||
ASSETS=$(echo $RESPONSE | jq -r '.[0].assets')
|
||||
# Number of assets
|
||||
NUMASSETS=$(echo $ASSETS | jq length)
|
||||
if [ $DEBUG ]; then echo "Assets:$NUMASSETS"; fi
|
||||
if [ $PRE = "true" ] ; then PRE="pre";
|
||||
else PRE=""; fi
|
||||
if [ $DRAFT = "true" ] ; then DRAFT="draft";
|
||||
else DRAFT=""; fi
|
||||
if [ $DEBUG ] ; then echo "pre:$PRE Draft:$DRAFT"; fi
|
||||
if [ $DEBUG ] ; then echo $REL; fi
|
||||
if [ "$REL" ] ; then line="$line $REL $ID $PRE $DRAFT $NUMASSETS"; fi
|
||||
if [ $SHOWCLONEURL ] ; then
|
||||
URL=$(echo $RESPONSE | jq -r '.[0].url')
|
||||
if [ "$URL" ] ; then line="$line $URL"; fi
|
||||
fi
|
||||
if [ $SHOWZIPURL ] ; then
|
||||
URL=$(echo $RESPONSE | jq -r '.[0].zipball_url')
|
||||
if [ "$URL" ] ; then line="$line $URL"; fi
|
||||
fi
|
||||
if [[ $NUMASSETS -gt 0 && $SHOWASSETURLS ]]; then
|
||||
ASSETURLS=$(echo $ASSETS | jq 'map("\(.name):\(.browser_download_url).")')
|
||||
if [ $DEBUG ]; then echo "$ASSETURLS"; fi
|
||||
# Turn the json into a list one on each line
|
||||
ASSETURLS=$(echo $ASSETURLS | sed 's/\[//' | sed 's/\]//' | sed 's/,/\\n/g' | sed 's/\"//g')
|
||||
line="$line\n$ASSETURLS";
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo -e $line;
|
||||
done
|
||||
255
git-make-release.sh
Executable file
255
git-make-release.sh
Executable file
@@ -0,0 +1,255 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# git-make-release.sh <organisation> <repo> <tagname> [usual options]
|
||||
#
|
||||
# Create the release (deleting one that is the same tag),
|
||||
# then uploads the .src.rpm and .rpm as an attachment (deleting any one of the same name)
|
||||
#
|
||||
#
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "git-make-release <modulename> <organization> <release> [local] [debug] [noisy] [draft] [prerelease]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git-make-release <modulename> <organization> <release> [local] [debug] [noisy] [draft] [prerelease]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
NOISY=
|
||||
EXTRAPARAMS=
|
||||
MAKEPRE=false
|
||||
MAKEDRAFT=false
|
||||
for param in $4 $5 $6; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
GITEAUser=${local_USER}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
noisy )
|
||||
NOISY=true ;;
|
||||
draft )
|
||||
MAKEDRAFT=true ;;
|
||||
prerelease )
|
||||
MAKEPRE=true ;;
|
||||
draftpre )
|
||||
MAKEPRE=true;MAKEDRAFT=true ;;
|
||||
* )
|
||||
EXTRAPARAMS=$EXTRAPARAMS" "$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $DEBUG ] ; then echo "draft:$MAKEDRAFT*pre:$MAKEPRE"; fi
|
||||
#check for release tag
|
||||
if [ -z $3 ]; then
|
||||
echo "Release tag not set";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ $NOISY ] ; then echo "make-release $1 $2 $3 $4 $5 $6" ; fi
|
||||
if [ $DEBUG ] ; then echo "************found ini file: $inifilename" ; fi
|
||||
# Make this null if you want lots of output. Still quite a bit anyway
|
||||
QUIET="-q"
|
||||
SILENT4CURL="-s"
|
||||
SILENT4MAKE="-s"
|
||||
if [ $DEBUG ] ; then
|
||||
QUIET=
|
||||
SILENT4CURL="-v"
|
||||
SILENT4MAKE=
|
||||
fi
|
||||
# Make this null to get curl to check ssl cert
|
||||
checkSSL="-k"
|
||||
|
||||
LOCALUser=${local_USER}
|
||||
if [[ $smegit_WORKDIR == ~* ]] ; then
|
||||
# relative to users home dir
|
||||
WORKDIR=$(echo ~)${smegit_WORKDIR:1}
|
||||
else
|
||||
# absolute path
|
||||
WORKDIR=${smegit_WORKDIR}
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "WORKDIR=$WORKDIR" ; fi
|
||||
RemoteRepoURL="$GITEAHOST/$2/$1"
|
||||
if [ $DEBUG ] ; then echo "URL="$RemoteRepoURL; fi
|
||||
|
||||
# First see if release exists:
|
||||
RESPONSE=$(curl -s -X 'GET' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases/tags/SME$3" \
|
||||
-H 'accept: application/json')
|
||||
if [ $DEBUG ] ; then echo "See if Release exists response="$RESPONSE; fi
|
||||
#parse result
|
||||
ID=""
|
||||
if echo "$RESPONSE" | jq empty >/dev/null 2>&1; then
|
||||
if echo "$RESPONSE" | jq 'has("errors")' | grep -q 'true'; then
|
||||
if [ $DEBUG ] ; then echo "Error detected:"; fi
|
||||
ERROR=$(echo "$RESPONSE" | jq '.message')
|
||||
if [ $DEBUG ] ; then echo "Error="$ERROR; fi
|
||||
elif echo "$RESPONSE" | jq 'has("id")' | grep -q 'true'; then
|
||||
if [ $DEBUG ] ; then echo "Id detected:"; fi
|
||||
ID=$(echo "$RESPONSE" | jq -r '.id')
|
||||
else
|
||||
echo "No error or id detected ($RESPONSE)."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Invalid JSON string ($RESPONSE)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$ID" ]]; then
|
||||
# Create Release
|
||||
if [ $NOISY ]; then echo "Creating Release $3 for $2/$1"; fi
|
||||
# 3 branches 'cos I can't get the ascaping correct for using $MAKEPRE and $MAKEDRAFT in the -d json parameter to curl!
|
||||
if [ $MAKEDRAFT = "true" ]; then
|
||||
if [ $DEBUG ] ; then echo "$MAKEDRAFT:Creating draft release"; fi
|
||||
RESPONSE=$(curl -s -X 'POST' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"body": "'"1st Draft Release of rpm built from git - `date` "'",
|
||||
"draft": true,
|
||||
"name": "'"$1"'",
|
||||
"prerelease": false,
|
||||
"tag_name": "'SME"$3"'",
|
||||
"target_commitish": ""}'
|
||||
);
|
||||
elif [ $MAKEPRE = "true" ]; then
|
||||
if [ $DEBUG ] ; then echo "Creating pre-release"; fi
|
||||
RESPONSE=$(curl -s -X 'POST' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"body": "'"1st Pre-Release of rpm built from git - `date` "'",
|
||||
"draft": false,
|
||||
"name": "'"$1"'",
|
||||
"prerelease": true,
|
||||
"tag_name": "'SME"$3"'",
|
||||
"target_commitish": ""}'
|
||||
);
|
||||
else
|
||||
if [ $DEBUG ] ; then echo "Creating full release"; fi
|
||||
RESPONSE=$(curl -s -X 'POST' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"body": "'"1st Stable Release of rpm built from git - `date` "'",
|
||||
"draft": false,
|
||||
"name": "'"$1"'",
|
||||
"prerelease": false,
|
||||
"tag_name": "'SME"$3"'",
|
||||
"target_commitish": ""}'
|
||||
);
|
||||
fi
|
||||
# Extract id from release
|
||||
if [ $DEBUG ]; then echo "Create Release response="$RESPONSE; fi
|
||||
exit 0
|
||||
ID=$(echo $RESPONSE | jq -r '.id')
|
||||
if [[ -z $ID ]] ; then
|
||||
echo "Unable to create release for $2/$1 ($3)"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if [ $NOISY ]; then echo "Found Release $ID for $2/$1 ($3)"; fi
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "ID:"$ID; fi
|
||||
|
||||
# And use it to upload the rpm and src rpm
|
||||
cd $WORKDIR/$2/$1
|
||||
# Got to cd to rpm directory here
|
||||
RPMDIR=$(ls $(basename `pwd`)*.rpm | sort | head -n 1 | sed 's/.src.rpm//' | sed 's/\./_/g')
|
||||
echo $RPMDIR
|
||||
# List the existing attachments
|
||||
ASSETSRESPONSE=$(curl -s -X 'GET' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases/$ID/assets" \
|
||||
-H 'accept: application/json')
|
||||
if [ $DEBUG ]; then echo "Asset response:"$ASSETSRESPONSE; fi
|
||||
NAMES=$(echo $ASSETSRESPONSE | jq -r '.[].name' | paste -sd "," -)
|
||||
if [ $DEBUG ]; then echo "Names:"$NAMES; fi
|
||||
if [ $DEBUG ]; then echo $(ls $RPMDIR/*.rpm); fi
|
||||
|
||||
FULLPATH=$(pwd);
|
||||
for File in $(ls $RPMDIR/*.rpm) ; do
|
||||
if [ $NOISY ]; then echo "Uploading $File"; fi
|
||||
BASEFile=$(basename $File)
|
||||
if [ $DEBUG ]; then echo $BASEFile; fi
|
||||
# Need to check if file is there already
|
||||
if [[ "$NAMES" == *"$BASEFile"* ]] ; then
|
||||
#Delete it - need the ID for it
|
||||
if [ $NOISY ]; then echo "Deleting $BASEFile from $1/$2 $3 ($ID) release"; fi
|
||||
ATTID=$(echo $ASSETSRESPONSE | jq -r '[ .[] | select(.name == "'"$BASEFile"'") | .id]')
|
||||
#echo "ATTID:"$ATTID
|
||||
ATTID=$(echo $ATTID | sed 's/\[//' | sed 's/\]//' | sed 's/ //g')
|
||||
if [ $DEBUG ]; then echo "ATTID:"$ATTID; fi
|
||||
RESPONSE=$(curl -s -X 'DELETE' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases/$ID/assets/$ATTID" \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'accept: application/json')
|
||||
if [ $DEBUG ]; then echo "DELETED Response:"$RESPONSE; fi
|
||||
if [[ -z $RESPONSE ]] ; then
|
||||
echo "Deleted $BASEFile from $1/$2 $3 ($ID) release"
|
||||
else
|
||||
echo "Delete failed $BASEFile from $2/$1 $3 ($ID) release ($RESPONSE)"
|
||||
fi
|
||||
else
|
||||
if [ $DEBUG ]; then echo "Did not find $BASEFile in \"$NAMES\""; fi
|
||||
fi
|
||||
# Then send current version
|
||||
FULLFILENAME=$FULLPATH/$File
|
||||
if [ $DEBUG ] ; then echo $FULLFILENAME; fi
|
||||
RESPONSE=$(curl -s -X 'POST' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases/$ID/assets?name=$BASEFile" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: multipart/form-data' \
|
||||
-F "attachment=@$FULLFILENAME;type=application/x-rpm")
|
||||
if [ $DEBUG ]; then echo "Send current version($File) response="$RESPONSE; fi
|
||||
if echo "$RESPONSE" | jq 'has("errors")' | grep -q 'true'; then
|
||||
ERROR=$(echo "$RESPONSE" | jq '.message')
|
||||
echo "$BASEFile not sucessfully uploaded ($ERROR)"
|
||||
else
|
||||
if [ $NOISY ]; then echo "$BASEFile sucessfully uploaded"; fi
|
||||
fi
|
||||
done
|
||||
146
git-migrate-repo.sh
Executable file
146
git-migrate-repo.sh
Executable file
@@ -0,0 +1,146 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Migrate (mirror) a remote repository
|
||||
#
|
||||
# migrate-repo.sh <reponame> <organisation> [<target organisation>]
|
||||
#
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "git_migrate-repo.sh <reponame> <organisation> [<target organization> <copy|mirror> <local> <debug>]"
|
||||
echo "will migrate repo to local user unless <target organisation> specified"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# get config file and params
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git_mirror-repo.sh <reponame> <organisation> [<target organisation>]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < $inifilename
|
||||
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == true ] ; then DEBUG=true ; fi
|
||||
if [ $DEBUG ] ; then echo "found ini file: $inifilename" ; fi
|
||||
|
||||
SILENT="-s"
|
||||
if [ $DEBUG ] ; then SILENT="-v" ; fi
|
||||
|
||||
SOURCEHOST=${remote_GITEAHOST}
|
||||
SOURCEACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
TARGETHOST=${local_GITEAHOST}
|
||||
TARGETACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
TARGETORG=${local_USER}
|
||||
MIRROR=false
|
||||
for param in $2 $3 $4 $5 $6; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
SOURCEHOST=${local_GITEAHOST}
|
||||
SOURCEACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
CLONEADDRESS=$LOCALGITEAHOST/$2/$1.git
|
||||
;;
|
||||
copy )
|
||||
MIRROR=false
|
||||
;;
|
||||
mirror )
|
||||
MIRROR=true ;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
* )
|
||||
TARGETORG=$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
CLONEADDRESS=$SOURCEHOST/$2/$1.git
|
||||
if [ $DEBUG ] ; then
|
||||
echo "MIRROR=$MIRROR"
|
||||
echo "TARGETORG=$TARGETORG"
|
||||
fi
|
||||
|
||||
# check that the TARGETORG exists
|
||||
if [ $DEBUG ] ; then echo "checking if $TARGETORG exists on $TARGETHOST" ; fi
|
||||
RESPONSE=$(curl $SILENT -o /dev/null -w "%{http_code}" $TARGETHOST/$TARGETORG)
|
||||
if [ $DEBUG ] ; then echo "RESPONSE=$RESPONSE" ; fi
|
||||
if [[ "$RESPONSE" != "200" ]] ; then
|
||||
echo "$TARGETORG does not exist on $TARGETHOST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# And check if this repo already exists on the target
|
||||
if [ $DEBUG ] ; then echo "checking if $TARGETORG/$1 already exists on $TARGETHOST" ; fi
|
||||
RESPONSE=$(curl $SILENT -o /dev/null -w "%{http_code}" $TARGETHOST/$TARGETORG/$1)
|
||||
if [ $DEBUG ] ; then echo "RESPONSE=$RESPONSE" ; fi
|
||||
if [ "$RESPONSE" == "200" ] ; then
|
||||
echo "Repository $TARGETORG/$1 already exists on $TARGETHOST - cannot migrate"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DATA=$(cat << EOT
|
||||
"auth_token": "$TARGETACCESSTOKEN",
|
||||
"clone_addr": "$CLONEADDRESS",
|
||||
"issues": true,
|
||||
"labels": true,
|
||||
"lfs": true,
|
||||
"milestones": true,
|
||||
"mirror": $MIRROR,
|
||||
"private": false,
|
||||
"pull_requests": true,
|
||||
"releases": true,
|
||||
"repo_name": "$1",
|
||||
"repo_owner": "$TARGETORG",
|
||||
"service": "git",
|
||||
"uid": 0,
|
||||
"wiki": true
|
||||
EOT
|
||||
)
|
||||
if [ $DEBUG ] ; then echo "JSON DATA=$DATA" ; fi
|
||||
|
||||
if [ $DEBUG ] ; then echo "Migrating $2/$1 as $TARGETORG/$1 on $TARGETHOST MIRROR=$MIRROR" ; fi
|
||||
RESPONSE=$(curl $SILENT -k -X 'POST' \
|
||||
"$TARGETHOST/api/v1/repos/migrate" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $TARGETACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{ $DATA }"
|
||||
)
|
||||
if [ $DEBUG ] ; then echo $? $RESPONSE ; fi
|
||||
|
||||
# And check if this repo is there
|
||||
if [ $DEBUG ] ; then echo "checking that $TARGETORG/$1 exists" ; fi
|
||||
RESPONSE=$(curl $SILENT -o /dev/null -w "%{http_code}" $TARGETHOST/$TARGETORG/$1)
|
||||
if [ $DEBUG ] ; then echo "RESPONSE=$RESPONSE" ; fi
|
||||
if [ "$RESPONSE" == "200" ] ; then
|
||||
msg="Repository $TARGETORG/$1 has been created"
|
||||
if [ $MIRROR == "true" ] ; then
|
||||
msg=$msg" and mirrors $2/$1"
|
||||
else
|
||||
msg=$msg" and is a copy of $2/$1"
|
||||
fi
|
||||
echo $msg
|
||||
else
|
||||
echo "migrate-repo was unable to migrate $2/$1 sucessfully"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Migrate (mirror) a remote repository
|
||||
#
|
||||
# migrate-repo.sh <reponame> <organisation> [<traget organisation>]
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ -z $inifilename ] ; then
|
||||
# Not here, look a bit further up
|
||||
echo "No ini file found $inifilename"
|
||||
echo "git-mirror-org.sh <source organisation> <target organisation> [<target organisation>]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "migrate-org.sh <source organisation> [<target organisation>]"
|
||||
echo "<target organisation> is optional and will default to the gitea user"
|
||||
exit 0
|
||||
fi
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == true ] ; then DEBUG=true ; fi
|
||||
if [ $DEBUG ] ; then echo "found ini file: $inifilename" ; fi
|
||||
|
||||
curlsilent="-s"
|
||||
if [ $DEBUG ] ; then curlsilent= ; fi
|
||||
|
||||
REMOTEACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
LOCALACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
REMOTEGITEAHOST=${remote_GITEAHOST}
|
||||
LOCALGITEAHOST=${local_GITEAHOST}
|
||||
TARGETORG=
|
||||
if [ $2 ] ; then TARGETORG=$2 ; fi
|
||||
|
||||
# check that the target organisation exists locally
|
||||
RESPONSE=$(curl $curlsilent -o /dev/null -w "%{http_code}" $LOCALGITEAHOST/$TARGETORG)
|
||||
if [[ "$RESPONSE" != "200" ]] ; then
|
||||
echo "$TARGETORG does not exist on $LOCALGITEAHOST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# get a list of repositories in the source organisation
|
||||
RESPONSE=$(curl $curlsilent -X 'GET' \
|
||||
"$REMOTEGITEAHOST/api/v1/orgs/$1/repos?limit=1000?per_page=200" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $REMOTEACCESSTOKEN"
|
||||
)
|
||||
|
||||
echo $RESPONSE | grep -oP '(?<="name":").+?(?=")' | while read repo; do
|
||||
echo "git-mirror-repo.sh ${repo} $1 $TARGETORG"
|
||||
done
|
||||
@@ -1,100 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Migrate (mirror) a remote repository
|
||||
#
|
||||
# migrate-repo.sh <reponame> <organisation> [<target organisation>]
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ -z $inifilename ] ; then
|
||||
# Not here
|
||||
echo "No ini file found $inifilename"
|
||||
echo "git_mirror-repo.sh <reponame> <organisation> [<target organisation>]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < $inifilename
|
||||
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "git_migrate-repo.sh <reponame> <organisation> [<target organization>]"
|
||||
echo "will migrate repo to ${local_USER} unless <target organisation> specified"
|
||||
exit 0
|
||||
fi
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == true ] ; then DEBUG=true ; fi
|
||||
if [ $DEBUG ] ; then echo "found ini file: $inifilename" ; fi
|
||||
|
||||
curlsilent="-s"
|
||||
if [ $DEBUG ] ; then curlsilent= ; fi
|
||||
|
||||
REMOTEUser=${remote_USER}
|
||||
REMOTEACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
LOCALACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
REMOTEGITEAHOST=${remote_GITEAHOST}
|
||||
CLONEADDRESS=$REMOTEGITEAHOST/$2/$1.git
|
||||
LOCALGITEAHOST=${local_GITEAHOST}
|
||||
NEWORG=${local_USER}
|
||||
if [ $3 ] ; then NEWORG=$3 ; fi
|
||||
|
||||
# check that the NEWORG exists
|
||||
RESPONSE=$(curl $curlsilent -o /dev/null -w "%{http_code}" $LOCALGITEAHOST/$NEWORG)
|
||||
if [[ "$RESPONSE" != "200" ]] ; then
|
||||
echo "$NEWORG does not exist on $LOCALGITEAHOST"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# And check if this repo already exists on the target
|
||||
RESPONSE=$(curl $curlsilent -o /dev/null -w "%{http_code}" $LOCALGITEAHOST/$NEWORG/$1)
|
||||
if [ "$RESPONSE" == "200" ] ; then
|
||||
echo "Repository $NEWORG/$1 already exists on $LOCALGITEAHOST - cannot migrate"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $DEBUG ] ; then echo "Mirroring $2/$1 as $NEWORG/$1 on $LOCALGITEAHOST" ; fi
|
||||
RESPONSE=$(curl $curlsilent -k -X 'POST' \
|
||||
"$LOCALGITEAHOST/api/v1/repos/migrate" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $LOCALACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"auth_token": "'"$REMOTEACCESSTOKEN"'",
|
||||
"clone_addr": "'"$CLONEADDRESS"'",
|
||||
"issues": true,
|
||||
"labels": true,
|
||||
"lfs": true,
|
||||
"milestones": true,
|
||||
"mirror": true,
|
||||
"private": false,
|
||||
"pull_requests": true,
|
||||
"releases": true,
|
||||
"repo_name": "'"$1"'",
|
||||
"repo_owner": "'"$NEWORG"'",
|
||||
"service": "git",
|
||||
"uid": 0,
|
||||
"wiki": true
|
||||
}')
|
||||
|
||||
if [ $DEBUG ] ; then echo $? $RESPONSE ; fi
|
||||
|
||||
# And check if this repo is there
|
||||
if [ $DEBUG ] ; then echo "checking that $NEWORG/$1 exists" ; fi
|
||||
RESPONSE=$(curl $curlsilent -o /dev/null -w "%{http_code}" $LOCALGITEAHOST/$NEWORG/$1)
|
||||
if [ "$RESPONSE" == "200" ] ; then
|
||||
echo "Repository $NEWORG/$1 has been created and mirrors $2/$1"
|
||||
else
|
||||
echo "migrate-repo was unable to migrate $2/$1 sucessfully"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
126
git-post-create-repo.sh
Executable file
126
git-post-create-repo.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Fiddle with the newly created repo to fix things that cannot be done throug the gitea template
|
||||
#
|
||||
# $1 = Module name e.g. smeserver-null
|
||||
# $2 = Organisation (smeserver or smecontrib)e
|
||||
# $3 = "local" will use parameters set for local repository else it will use remote
|
||||
#
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "************git-post-create-repo.sh <modulename> <organization> [<local>]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "*git-post-create-repo.sh <modulename> <organization> [<local>]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
|
||||
LOCALUser=${local_USER}
|
||||
if [[ $smegit_WORKDIR == ~* ]] ; then
|
||||
# relative to users home dir
|
||||
WORKDIR=$(echo ~)${smegit_WORKDIR:1}
|
||||
else
|
||||
# absolute path
|
||||
WORKDIR=${smegit_WORKDIR}
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "WORKDIR=$WORKDIR" ; fi
|
||||
GITEAUser=$remote_USER
|
||||
GITEAACCESSTOKEN=$remote_GITEAACCESSTOKEN
|
||||
GITEAHOST=$remote_GITEAHOST
|
||||
if [ $3 ] ; then
|
||||
if [ "$3" == "local" ] ; then
|
||||
GITEAUser=$local_USER
|
||||
GITEAACCESSTOKEN=$local_GITEAACCESSTOKEN
|
||||
GITEAHOST=$local_GITEAHOST
|
||||
fi
|
||||
fi
|
||||
RemoteRepoURL="$GITEAHOST/$2/$1"
|
||||
cd $WORKDIR/$2/$1
|
||||
echo `pwd`
|
||||
|
||||
# Rename the spec file accordingly to $1
|
||||
mv change-this-to-the-package-name.spec $1.spec
|
||||
|
||||
# Set the date in the spec file changelog to today
|
||||
dateH=`date "+%a %b %d %Y"`
|
||||
sed -i "s/Day MMMM DD YYYY/$dateH/" $1.spec
|
||||
|
||||
#Now write them all back to the repo
|
||||
|
||||
git add -A
|
||||
git status
|
||||
git commit -m "post create changes"
|
||||
git push
|
||||
|
||||
# and fix up the external links to the Wiki and the Issues
|
||||
# (this is a bug that I have logged) - they say is not supported.
|
||||
|
||||
TARGETPKG=$1
|
||||
if [[ "$2" == "smecontribs" ]]; then
|
||||
BASEORCONTRIB="contribs10"
|
||||
PRODUCTBUGZILLA="SME%20Contribs"
|
||||
else
|
||||
BASEORCONTRIB="sme10"
|
||||
PRODUCTBUGZILLA="SME%20Server%2010.X"
|
||||
fi
|
||||
TARGETORG=brianr
|
||||
PRODUCTBUGZILLA=
|
||||
WIKILINK="https://wiki.koozali.org"
|
||||
RESPONSE=$(curl -X 'PATCH' \
|
||||
"$GITEAHOST/api/v1/repos/$TARGETORG/$TARGETPKG" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"description": "'"SMEServer Koozali developed repo for $TARGETPKG base"'",
|
||||
"has_issues": true,
|
||||
"external_tracker": {
|
||||
"external_tracker_format": "https://bugs.koozali.org/show_bug.cgi?id={index}",
|
||||
"external_tracker_style": "numeric",
|
||||
"external_tracker_url": "'"https://bugs.koozali.org/buglist.cgi?component=$TARGETPKG&product=$PRODUCTBUGZILLA"'"
|
||||
},
|
||||
"has_wiki": true,
|
||||
"external_wiki": {
|
||||
"external_wiki_url": "'"$WIKILINK"'"
|
||||
}
|
||||
}'
|
||||
)
|
||||
echo $RESPONSE
|
||||
|
||||
#That's All for now folks!!
|
||||
exit 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
176
git-retag.sh
Executable file
176
git-retag.sh
Executable file
@@ -0,0 +1,176 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# $1 = Module name e.g. smeserver-ddclient
|
||||
# $2 = Organisation (smeserver or smecontrib)e
|
||||
# optional (can be in any order)
|
||||
# <local> will use parameters set for local repository else it will use remote
|
||||
# <purge> will purge all old tags
|
||||
# <debug> turn on debug regardless of ~/.smegit/config
|
||||
# <noisy> print a line showing how it was called
|
||||
# Module name must exist
|
||||
#
|
||||
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "************git-retag.sh <modulename> <organization> [<local> | <purge> | <debug> | <noisy>]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#Needs /usr/bin/rpmspec
|
||||
if command -v /usr/bin/rpmspec > /dev/null; then
|
||||
if [ $DEBUG ] ; then echo "************rpmspec is installed" ; fi
|
||||
else
|
||||
echo "ERROR********************** rpmspec is not installed ******************"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git-retag.sh <modulename> <organization> [<local> | <purge> | <debug> | <noisy>]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
|
||||
REPO_NAME=$1
|
||||
ORGGITEA=$2
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
NOISY=
|
||||
CLEAN=
|
||||
EXTRAPARAMS=
|
||||
for param in $3 $4 $5 $6 ; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
GITEAUser=${local_USER}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
noisy )
|
||||
NOISY=true ;;
|
||||
purge )
|
||||
CLEAN=true ;;
|
||||
* )
|
||||
echo "Unkown parameter: $param"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $NOISY ] ; then echo "git-retag.sh $1 $2 $3 $4 $5 $6" ; fi
|
||||
if [ $DEBUG ] ; then echo "************found ini file: $inifilename" ; fi
|
||||
# Make this null if you want lots of output. Still quite a bit anyway
|
||||
QUIET="-q"
|
||||
SILENT4CURL="-s"
|
||||
SILENT4MAKE="-s"
|
||||
if [ $DEBUG ] ; then
|
||||
QUIET=
|
||||
SILENT4CURL="-v"
|
||||
SILENT4MAKE=
|
||||
fi
|
||||
# Make this null to get curl to check ssl cert
|
||||
checkSSL="-k"
|
||||
|
||||
LOCALUser=${local_USER}
|
||||
if [[ $smegit_WORKDIR == ~* ]] ; then
|
||||
# relative to users home dir
|
||||
WORKDIR=$(echo ~)${smegit_WORKDIR:1}
|
||||
else
|
||||
# absolute path
|
||||
WORKDIR=${smegit_WORKDIR}
|
||||
fi
|
||||
if [ $DEBUG ] ; then echo "WORKDIR=$WORKDIR" ; fi
|
||||
RemoteRepoURL="$GITEAHOST/$ORGGITEA/$REPO_NAME"
|
||||
|
||||
# Make sure credentials taken from store
|
||||
# The first time you pull or push it will ask for credentials and then save them in a file.
|
||||
git config --global credential.helper store
|
||||
|
||||
# Create the local Git repository
|
||||
GITFiles=$WORKDIR/$ORGGITEA
|
||||
mkdir -p $GITFiles
|
||||
cd $GITFiles
|
||||
|
||||
# Delete the local first
|
||||
if [ -d "$REPO_NAME" ] ; then
|
||||
if [ $DEBUG ] ; then echo "************Deleting local GIT files" ; fi
|
||||
rm -Rf $GITFiles/$REPO_NAME
|
||||
fi
|
||||
|
||||
# See if it exists on the Gitea host
|
||||
if [ $DEBUG ] ; then echo "check that $GITEAHOST/$ORGGITEA/$REPO_NAME exists" ; fi
|
||||
RESPONSE=$(curl $checkSSL $SILENT4CURL -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$ORGGITEA/$REPO_NAME")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
if [ $DEBUG ] ; then echo "************Repository for $REPO_NAME exists, cloning!" ; fi
|
||||
# If so, clone it (just want the README.md)
|
||||
if [ $DEBUG ] ; then echo "git clone $GITEAHOST/$ORGGITEA/$REPO_NAME.git" ; fi
|
||||
cd $GITFiles
|
||||
git clone "$GITEAHOST/$ORGGITEA/$REPO_NAME.git"
|
||||
else
|
||||
echo "************Repository for $ORGGITEA/$REPO_NAME does not exist. Aborting $RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $GITFiles/$REPO_NAME
|
||||
if [ $CLEAN ] ; then
|
||||
# read the existing tags
|
||||
OLDTAGS=$(git tag --list)
|
||||
# delete old tag/s
|
||||
for tag in $OLDTAGS ; do
|
||||
if [ $DEBUG ] ; then echo "Removing tag $tag" ; fi
|
||||
git tag --delete $tag
|
||||
git push origin --delete $tag
|
||||
git push --tags
|
||||
done
|
||||
fi
|
||||
# Now create the version and release tag from the specfile
|
||||
VERSION_RELEASE_LONG=`rpm --queryformat '%{version} %{release}\n' --specfile $REPO_NAME.spec`
|
||||
VERSION_RELEASE=${VERSION_RELEASE_LONG%%$'\n'*}
|
||||
VERSION=${VERSION_RELEASE% *}
|
||||
VERSION=${VERSION//./_}
|
||||
RELEASE=${VERSION_RELEASE#* }
|
||||
TAG=$VERSION"-"${RELEASE%.*}"_el8_sme"
|
||||
if [ $DEBUG ] ; then
|
||||
echo "VERSION_RELEASE=$VERSION_RELEASE"
|
||||
echo "VERSION=$VERSION"
|
||||
echo "RELEASE=$RELEASE"
|
||||
echo "TAG=$TAG"
|
||||
fi
|
||||
git pull
|
||||
git tag -a $TAG -m "Setting tag to current Version-Release in spec file: $TAG"
|
||||
git push origin --tag $TAG $QUIET
|
||||
|
||||
echo "Current $ORGGITEA/$REPO_NAME tagged as $TAG"
|
||||
if [ $CLEAN ] ; then echo " - old tags removed" ; fi
|
||||
exit 0
|
||||
178
git-transfer-repo.sh
Executable file
178
git-transfer-repo.sh
Executable file
@@ -0,0 +1,178 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Transfer a repo to a different user (or organisation)
|
||||
# $1 = Module name e.g. e-smith-dnscache
|
||||
# $2 = Source Organisation (any valid organisation or user)
|
||||
# $3 = Target Organisation (any valid organisation or user - you need owner privileges)
|
||||
# $4-$7 can appear in any order and are optional
|
||||
# = "local" will use parameters set for local repository else it will use remote
|
||||
# = "force" will automagically delete an existing repo, otherwise it will prompt
|
||||
# = "debug" run in debug mode
|
||||
# = "silent" suppress success message
|
||||
#
|
||||
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "Transfer a repo to a different user (or organisation)"
|
||||
echo "git-transfer-repo.sh <repository> <source organization> ,target organisation> [<local> <force> <debug> <silent>]"
|
||||
echo "<repository> = repository name (e.g. smeserver-clamav)"
|
||||
echo "<source organisation> (any valid organisation or user)"
|
||||
echo "<target organisation> (any valid organisation or user - you need owner privileges)"
|
||||
echo " can appear in any order and are optional"
|
||||
echo " - <local> will use parameters set for local repository, else it will use remote"
|
||||
echo " - <force> will automagically delete an existing target repo, otherwise it will prompt"
|
||||
echo " - <debug> run in debug mode"
|
||||
echo " - <silent> suppress success message"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git-cvs2git.sh <modulename> <organization> [<local>]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
if [ $DEBUG ] ; then echo "************found ini file: $inifilename" ; fi
|
||||
|
||||
if [[ $smegit_WORKDIR == ~* ]] ; then
|
||||
# relative to users home dir
|
||||
WORKDIR=$(echo ~)${smegit_WORKDIR:1}
|
||||
else
|
||||
# absolute path
|
||||
WORKDIR=${smegit_WORKDIR}
|
||||
fi
|
||||
|
||||
# Command line parameters
|
||||
REPO=$1
|
||||
SOURCEORG=$2
|
||||
TARGETORG=$3
|
||||
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
DELETEIT=
|
||||
NOOUTPUT=
|
||||
for param in $4 $5 $6 $7; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
;;
|
||||
force )
|
||||
DELETEIT=true ;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
silent )
|
||||
NOOUTPUT=true ;;
|
||||
* )
|
||||
echo "Ignoring $param" ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Debug settings
|
||||
# Make this null if you want lots of output. Still quite a bit anyway
|
||||
QUIET="--quiet"
|
||||
SILENT="-s"
|
||||
if [ $DEBUG ] ; then
|
||||
QUIET=
|
||||
SILENT="-v"
|
||||
fi
|
||||
# Make this null to get curl to check ssl cert
|
||||
checkSSL="-k"
|
||||
|
||||
#Check that source package exists
|
||||
if [ $DEBUG ] ; then echo "Check if $SOURCEORG/$REPO is there!" ; fi
|
||||
RESPONSE=$(curl $SILENT -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$SOURCEORG/$REPO")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
if [ $DEBUG ] ; then echo "Repository for $SOURCEORG/$REPO exists!" ; fi
|
||||
else
|
||||
echo "************Repository for $SOURCEORG/$REPO does not exist on $GITEAHOST ($RESPONSE)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $DEBUG ] ; then echo "Transferring $TARGETORG/$REPO to $SOURCEORG/$REPO" ; fi
|
||||
#Check that target repo does not exist
|
||||
if [ $DEBUG ] ; then echo "Check if $TARGETORG/$REPO is there!" ; fi
|
||||
RESPONSE=$(curl $SILENT -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$TARGETORG/$REPO")
|
||||
EXISTS=
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
EXISTS=true
|
||||
if [ $DEBUG ] ; then echo "Repository for $TARGETORG/$REPO exists!" ; fi
|
||||
if [ -z ${DELETEIT} ] ; then
|
||||
while true; do
|
||||
read -p "$TARGETORG/$REPO exists! Do you wish to delete it and continue?(y/n) " yn
|
||||
case $yn in
|
||||
[Yy]* )
|
||||
DELETEIT=true
|
||||
break ;;
|
||||
[Nn]* )
|
||||
DELETEIT=
|
||||
break ;;
|
||||
* ) echo "Please answer yes or no.";;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
if [ $DELETEIT ] ; then
|
||||
if [ $DEBUG ] ; then echo "Deleting $TARGETORG/$REPO" ; fi
|
||||
RESPONSE=$(curl "$checkSSL" "$SILENT" -o /dev/null -w "%{http_code}" -X 'DELETE' \
|
||||
"$GITEAHOST/api/v1/repos/$TARGETORG/$REPO" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" )
|
||||
if [[ $RESPONSE != "204" ]] ; then
|
||||
echo "Unable to delete $TARGETORG/$REPO ($RESPONSE)"
|
||||
else
|
||||
EXISTS=
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ $DEBUG ] ; then echo "Repository for $SOURCEORG/$REPO does not exist on $GITEAHOST" ; fi
|
||||
fi
|
||||
|
||||
# Transfer the repo
|
||||
if [[ -z $EXISTS ]] ; then
|
||||
if [ $DEBUG ] ; then echo "Actual Transfer" ; fi
|
||||
RESPONSE=$(curl "$SILENT" "$checkSSL" -o /dev/null -w "%{http_code}" -X 'POST' \
|
||||
"$GITEAHOST/api/v1/repos/$SOURCEORG/$REPO/transfer" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"new_owner": "'"$TARGETORG"'"
|
||||
}'
|
||||
)
|
||||
fi
|
||||
if [[ $EXISTS || $RESPONSE != "202" ]] ; then
|
||||
echo "Unable to transfer $SOURCEORG/$REPO to $TARGETORG/$REPO ($RESPONSE) - Aborting!"
|
||||
exit 1
|
||||
else
|
||||
if [[ -z $NOOUTPUT ]] ; then echo "$SOURCEORG/$REPO has been transferred to $TARGETORG/$REPO" ; fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
121
git-update-release-in-one-repo.sh
Executable file
121
git-update-release-in-one-repo.sh
Executable file
@@ -0,0 +1,121 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# git-update-release-in-one-repo.sh <organisation> <repo> [ <releasetag> | <id> ] [draft|prerelease|release]
|
||||
#
|
||||
# Create the release (deleting one that is the same tag),
|
||||
# then uploads the .src.rpm and .rpm as an attachment (deleting any one of the same name)
|
||||
#
|
||||
#
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "git-update-release-in-one-repo.sh <organisation> <repo> [ <releasetag> | <id> ] [draft|prerelease|release] [local] [debug]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -z $4 ]] ; then
|
||||
echo "Must provide release type"
|
||||
echo "git-update-release-in-one-repo.sh <organisation> <repo> [ <releasetag> | <id> ] [draft|prerelease|release] [local] [debug]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
echo "git-update-release-in-one-repo.sh <organisation> <repo> [ <releasetag> | <id> ] [draft|prerelease|release] [local] [debug]"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
|
||||
DEBUG=
|
||||
if [ ${smegit_DEBUG} == "true" ] ; then DEBUG=true ; fi
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
for param in $2 $3 $4 $5 $6 $7; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
local )
|
||||
GITEAUser=${local_USER}
|
||||
GITEAACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
* )
|
||||
EXTRAPARAMS=$EXTRAPARAMS" "$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Uses if ist char is numeric to see if an id or tag is provided
|
||||
if [[ ! "${3:0:1}" =~ [0-9] ]]; then
|
||||
# <organisation> <repo> <releasetag> - find the id from the info provided
|
||||
ID=999;
|
||||
# TBD
|
||||
else
|
||||
ID=$3;
|
||||
fi
|
||||
|
||||
if [ $DEBUG ]; then echo "I:$ID"; fi
|
||||
|
||||
# And then edit it by id.
|
||||
|
||||
if [ $4 = "draft" ]; then
|
||||
RESPONSE=$(curl -s -X 'PATCH' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases/$ID" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"draft": true,
|
||||
"prerelease": false
|
||||
}')
|
||||
elif [ $4 = "prerelease" ]; then
|
||||
RESPONSE=$(curl -s -X 'PATCH' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases/$ID" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"draft": false,
|
||||
"prerelease": true
|
||||
}')
|
||||
else
|
||||
RESPONSE=$(curl -s -X 'PATCH' \
|
||||
"$GITEAHOST/api/v1/repos/$2/$1/releases/$ID" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $GITEAACCESSTOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"draft": false,
|
||||
"prerelease": false
|
||||
}')
|
||||
fi
|
||||
if [ $DEBUG ]; then echo "$RESPONSE"; fi
|
||||
exit 0
|
||||
|
||||
|
||||
1254
gitea_to_github_sync.py
Normal file
1254
gitea_to_github_sync.py
Normal file
File diff suppressed because it is too large
Load Diff
17
github PR instructions
Normal file
17
github PR instructions
Normal file
@@ -0,0 +1,17 @@
|
||||
1. Goto Koozali-SME-Server organisation on Github
|
||||
2. Go into the Repo for the Component you want to change
|
||||
3. Make sure that the default branch for the repo is "Master" - use the menu settings to change this if necessary (if you can)
|
||||
4. fork the repo to your own user, make sure that "copy the master branch only" is set.
|
||||
5. Make whatever source code changes you want by using the github editor.
|
||||
6. Press "Commit changes", adding a description of the commit and making sure you are sewlecting "Commit directly..."
|
||||
8. Press "This branch is 1 commit ahead of"
|
||||
9. Examine diff to make sure the changes are what you expect.
|
||||
10. Note that the header shows that the realtionship betwen the base repo and your fork
|
||||
11. To create the pull request (which goes back to the base repo), click on "Create pull request"
|
||||
12 Add title and description (it needs title for Create pull request button to be enabled)
|
||||
13 Press "Create pull request". This should enter an entry in the pull requests, plus close the request, plus create a bug on the Koozali Bugzilla
|
||||
14 Probably shouild delee your Fork once you have got the PR across, as it will be out of date as soon as any updates come to the base repo.
|
||||
|
||||
|
||||
|
||||
|
||||
194
github-make-push-mirror.sh
Executable file
194
github-make-push-mirror.sh
Executable file
@@ -0,0 +1,194 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# $1 = Module name e.g. smeserver-ddclient (assumes github repo is to be called the same)
|
||||
# $2 = gitea Organisation (smeserver or smecontrib)
|
||||
# $3 = github Organisation (Koozali-SME-Server or Koozali-SME-Server-contribs or smeserver)
|
||||
#
|
||||
|
||||
# Make this null to get curl to check ssl cert
|
||||
checkSSL="-k"
|
||||
# and -v for curl verbose mode
|
||||
SILENT4CURL="-s"
|
||||
|
||||
if [ "$#" -ne 3 ]; then
|
||||
echo "Error: github-make-push-mirror.sh <modulename> <organization> <github orgamisation>"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check that jq is installed
|
||||
if command -v jq -V > /dev/null; then
|
||||
if [ $DEBUG ] ; then echo "Jq is installed" ; fi
|
||||
else
|
||||
echo "Error: jq is not installed (try EPEL)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#check gh is loaded
|
||||
if command -v gh --version > /dev/null; then
|
||||
if [ $DEBUG ] ; then echo "gh is installed" ; fi
|
||||
else
|
||||
echo "Error: gh is not installed **************"
|
||||
echo "try: curl -fsSL https://cli.github.com/packages/rpm/gh-cli.repo | sudo tee /etc/yum.repos.d/github-cli.repo"
|
||||
echo "then:sudo dnf -y install gh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Pull in parameters from a config file ~/.smegit/config
|
||||
#
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]]
|
||||
then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]]
|
||||
then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
|
||||
GITEAUser=${remote_USER}
|
||||
GITEAACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
|
||||
#First check repo name exists in gitea
|
||||
REPO_NAME=$1
|
||||
RESPONSE=$(curl $checkSSL $SILENT4CURL -o /dev/null -w "%{http_code}" "$GITEAHOST/api/v1/repos/$2/$REPO_NAME")
|
||||
if [ "$RESPONSE" == "200" ]; then
|
||||
echo "$2/$1 exists in GITEA"
|
||||
else
|
||||
echo "Error: $2/$1 does not exists in GITEA"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# and that the github token has been installed in the .smegit file
|
||||
# Note that this personal access token is generated by github against a particular login
|
||||
GITHUBLOGIN=${remote_GITHUBLOGIN}
|
||||
if [ -z "${remote_GITHUBTOKEN}" ]; then
|
||||
echo "Error: The GITHUBTOKEN is not defined in .smegit/config ."
|
||||
fi
|
||||
|
||||
#and check that github is logged in
|
||||
if ! gh auth status > /dev/null 2>&1; then
|
||||
echo "You must log in with GitHub CLI first."
|
||||
echo "Run 'gh auth login' and follow the instructions."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# first create repo on github or skip over if already created
|
||||
REPO_NAME=$3/$1
|
||||
DESCRIPTION="Repo-$1 - push mirror from Koozali gitea repo $1"
|
||||
|
||||
# Create the repository
|
||||
|
||||
# Check if the repository exists
|
||||
repo_exists=$(gh repo view "$REPO_NAME" > /dev/null 2>&1)
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "The repository '$REPO_NAME' already exists."
|
||||
else
|
||||
echo "Creating GitHub repository '$REPO_NAME'..."
|
||||
gh repo create "$REPO_NAME" --description "$DESCRIPTION" --public
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "GitHub Repository '$REPO_NAME' created successfully."
|
||||
else
|
||||
echo "Failed to create repository '$REPO_NAME'."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Now update the equivalent gitea repo to push to the github one.
|
||||
GITHUB_REPO_URL="https://github.com/$3/$1.git"
|
||||
|
||||
# API endpoint to create a push mirror
|
||||
API_ENDPOINT="${remote_GITEAHOST}/api/v1/repos/${2}/${1}/push_mirrors"
|
||||
|
||||
# See if the push mirror exists already
|
||||
# Fetch repository mirror settings using the Gitea API
|
||||
response=$(curl $checkSSL $SILENT4CURL -s -H "Authorization: token ${remote_GITEAACCESSTOKEN}" \
|
||||
"$API_ENDPOINT")
|
||||
|
||||
if [ -z "$response" ]; then
|
||||
echo "Failed to fetch mirror settings from Gitea."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if there are any push mirrors
|
||||
push_mirrors=$(echo "$response" | jq -r '.[] | select(.sync_on_commit == true)')
|
||||
|
||||
if [ -z "$push_mirrors" ]; then
|
||||
echo "No push mirror configurations found for the repository '$2/$1'."
|
||||
else
|
||||
echo "Push mirror configurations found for the repository '$2/$1:"
|
||||
#echo "$push_mirrors" | jq
|
||||
fi
|
||||
|
||||
# check if one of them is the one to github
|
||||
github_mirror=$(echo "$response" | jq -r --arg address "${GITHUB_REPO_URL}" '.[] | select(.remote_address == $address)')
|
||||
if [ -z "$github_mirror" ]; then
|
||||
echo "No push mirror configuration with remote address '${GITHUB_REPO_URL}' found for the repository '$REPO_NAME'."
|
||||
else
|
||||
echo "Push mirror configuration with remote address '${GITHUB_REPO_URL}' found for the repository '$REPO_NAME':"
|
||||
echo "$github_mirror" | jq
|
||||
remote_name=$(echo "$github_mirror" | jq -r '.remote_name')
|
||||
echo "Deleting this push mirror entry with remote_name: $remote_name"
|
||||
# Delete the mirror using the mirror ID
|
||||
delete_response=$(curl $checkSSL $SILENT4CURL -s -X DELETE -H "Authorization: token ${remote_GITEAACCESSTOKEN}" \
|
||||
"$API_ENDPOINT/$remote_name")
|
||||
if [ -z "$delete_response" ]; then
|
||||
echo "Successfully deleted the mirror with remote name '$remote_name'."
|
||||
else
|
||||
echo "Failed to delete the mirror with remote name '$remote_name'. Response: $delete_response"
|
||||
fi
|
||||
fi
|
||||
|
||||
# JSON payload to be sent to the Gitea API to create the push mirrir
|
||||
MIRROR_PAYLOAD=$(cat <<EOF
|
||||
{
|
||||
"interval" : "8h0m0s",
|
||||
"remote_address": "${GITHUB_REPO_URL}",
|
||||
"remote_username": "${GITHUBLOGIN}",
|
||||
"remote_password": "${remote_GITHUBTOKEN}",
|
||||
"sync_on_commit" : true
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# Create the push mirror
|
||||
response=$(curl $checkSSL $SILENT4CURL -s -w "\nHTTP_STATUS_CODE:%{http_code}" -X POST "$API_ENDPOINT" \
|
||||
-H "Authorization: token ${remote_GITEAACCESSTOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$MIRROR_PAYLOAD")
|
||||
|
||||
# Extract the response and HTTP status code
|
||||
echo "Creating the push mirror for $2/$1 to $3/$1"
|
||||
body=$(echo "$response" | sed -n '1,/HTTP_STATUS_CODE:/p' | sed '$d')
|
||||
status_code=$(echo "$response" | grep "HTTP_STATUS_CODE:" | awk -F ':' '{print $2}')
|
||||
|
||||
# Evaluate the response
|
||||
if [[ "$status_code" -ge 200 && "$status_code" -lt 300 ]]; then
|
||||
echo "Successfully set up push mirror from Gitea repository to GitHub for $2/$1 to $3/$1."
|
||||
else
|
||||
echo "Failed to set up push mirror. HTTP Status Code: $status_code"
|
||||
echo "Response: $body"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
127
parse-list.sh
Executable file
127
parse-list.sh
Executable file
@@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Run script against every item in input file
|
||||
|
||||
if [[ -z $1 ]] ; then
|
||||
echo "parse a list of parameters and execute script with those parameters"
|
||||
echo "parse-list.sh <param file> <script> [<noisy> <additional> <additional> <additional>]"
|
||||
echo "<param file|org='organisation'> name of file containing parameters"
|
||||
echo " or the organisation list of repos"
|
||||
echo "<script> script to run (e.g. rename-e-smith-pkh.sh)"
|
||||
echo "optional params can appear in any order"
|
||||
echo " <review> show line being executed but do NOTHING!"
|
||||
echo " <noisy> show line being executed"
|
||||
echo " <additional> additional params to be passed (up to 3)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# parse the command line parameters
|
||||
PROCESSORG=
|
||||
EXTRAPARAMS=
|
||||
if [[ $1 == org=* ]] ; then
|
||||
# using a list of the repos in this organisatoin as input
|
||||
PROCESSORG=${1#*=}
|
||||
EXTRAPARAMS=$PROCESSORG # add the org as the first additional param
|
||||
# Get the ini file and relevant parameters - only needed for org processing
|
||||
inifilename=$(echo ~)"/.smegit/config"
|
||||
if [ ! -e $inifilename ] ; then
|
||||
# Not here, look at system default
|
||||
if [ ! -e /etc/smegit.ini ] ; then
|
||||
echo "No ini file found $inifiename or /etc/smegit.ini"
|
||||
exit 1
|
||||
else
|
||||
initfilename="/etc/smegit.ini"
|
||||
fi
|
||||
fi
|
||||
|
||||
while read -r line || [[ -n "$line" ]]; do
|
||||
if [[ $line =~ ^\[.*\]$ ]] ; then
|
||||
section=${line#*[}
|
||||
section=${section%]*}
|
||||
else
|
||||
if [[ $line =~ ^[^#]*= ]] ; then
|
||||
key=${line%=*}
|
||||
value=${line#*=}
|
||||
declare "${section}_${key}=$value"
|
||||
fi
|
||||
fi
|
||||
done < "$inifilename"
|
||||
else
|
||||
# using a file as input
|
||||
if [[ ! -f $1 ]] ; then
|
||||
echo "Can NOT find $1 - Aborting"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $(which $2 | grep "no $2") ]] ; then
|
||||
echo "Can NOT find $2 - Aborting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEBUG=
|
||||
REVIEW=
|
||||
NOISY=
|
||||
GITEAHOST=${remote_GITEAHOST}
|
||||
ACCESSTOKEN=${remote_GITEAACCESSTOKEN}
|
||||
for param in $3 $4 $5 $6; do
|
||||
if [ $param ] ; then
|
||||
case $param in
|
||||
review )
|
||||
REVIEW=true ;;
|
||||
noisy )
|
||||
NOISY=true ;;
|
||||
local )
|
||||
GITEAHOST=${local_GITEAHOST}
|
||||
ACCESSTOKEN=${local_GITEAACCESSTOKEN}
|
||||
EXTRAPARAMS=$EXTRAPARAMS" "$param
|
||||
;;
|
||||
debug )
|
||||
DEBUG=true ;;
|
||||
* )
|
||||
EXTRAPARAMS=$EXTRAPARAMS" "$param ;;
|
||||
esac
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Build array of parameters to cycle through
|
||||
PARAMLIST=()
|
||||
if [ $PROCESSORG ] ; then
|
||||
# get a list of repositories in the source organisation and store in array of parameters
|
||||
for page in {1..10} ; do
|
||||
if [ $DEBUG ] ; then echo "getting page $page of repos from $GITEAHOST $PROCESSORG" ; fi
|
||||
RESPONSE=$(curl -s -X 'GET' \
|
||||
"$GITEAHOST/api/v1/orgs/$PROCESSORG/repos?page=$page" \
|
||||
-H 'accept: application/json' \
|
||||
-H "Authorization: token $ACCESSTOKEN"
|
||||
)
|
||||
if [ $DEBUG ] ; then echo "RESPONSE=$RESPONSE" ; fi
|
||||
|
||||
if [[ $RESPONSE == '[]' ]] ; then
|
||||
# we have them all
|
||||
break
|
||||
else
|
||||
PARAMLIST="$PARAMLIST $(echo $RESPONSE | grep -oP '(?<="name":").+?(?=")')"
|
||||
fi
|
||||
done
|
||||
else
|
||||
# load array of parameters from input file
|
||||
while read -r line ; do PARAMLIST+=($line) ; done < $1
|
||||
fi
|
||||
|
||||
# Cycle through array of parameters and execute script
|
||||
for param in ${PARAMLIST[@]}
|
||||
do
|
||||
if [[ $NOISY || $REVIEW ]] ; then echo "$2 $param $EXTRAPARAMS" ; fi
|
||||
if [[ -z $REVIEW ]] ; then
|
||||
if [[ $param ]] ; then
|
||||
RESPONSE=$($2 $param $EXTRAPARAMS) ; rc=$?
|
||||
if [ $rc -ne 0 ] ; then echo "($rc)\n$RESPONSE" ; fi
|
||||
if [ $DEBUG ] ; then echo "RESPONSE=$RESPONSE" ; fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
5
require_server.txt
Normal file
5
require_server.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
fastapi>=0.111.0
|
||||
uvicorn>=0.23.2
|
||||
httpx>=0.27.0
|
||||
PyGithub>=2.3.0
|
||||
python-dotenv>=1.0.1
|
||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
PyGithub>=2.3.0
|
||||
httpx>=0.27.0
|
||||
PyYAML>=6.0.1
|
||||
fastapi>=0.111.0
|
||||
uvicorn>=0.23.0
|
||||
691
webhook_endpoint.py
Normal file
691
webhook_endpoint.py
Normal file
@@ -0,0 +1,691 @@
|
||||
|
||||
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import json
|
||||
import base64
|
||||
import sqlite3
|
||||
import logging
|
||||
import hmac
|
||||
import hashlib
|
||||
import contextlib
|
||||
from typing import Optional, Tuple, Dict, Any, List
|
||||
|
||||
import httpx
|
||||
from fastapi import FastAPI, Header, HTTPException, Request
|
||||
from fastapi.responses import JSONResponse, PlainTextResponse
|
||||
from github import Github, Auth
|
||||
|
||||
# ---------------- Logging (UTC) ----------------
|
||||
|
||||
class UTCFormatter(logging.Formatter):
|
||||
def formatTime(self, record, datefmt=None):
|
||||
import datetime as dt
|
||||
from datetime import timezone
|
||||
ts = dt.datetime.fromtimestamp(record.created, tz=timezone.utc)
|
||||
return ts.isoformat(timespec="seconds").replace("+00:00", "Z")
|
||||
|
||||
def configure_logging():
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(UTCFormatter("[%(asctime)s] %(levelname)s %(message)s"))
|
||||
root = logging.getLogger()
|
||||
root.handlers.clear()
|
||||
root.addHandler(handler)
|
||||
level = os.environ.get("LOG_LEVEL", "INFO").upper()
|
||||
root.setLevel(getattr(logging, level, logging.INFO))
|
||||
|
||||
configure_logging()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# ---------------- Config via env ----------------
|
||||
|
||||
GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", "").strip()
|
||||
if not GITHUB_TOKEN:
|
||||
logger.warning("GITHUB_TOKEN is not set. You must set it unless GITHUB_DRY_RUN=true.")
|
||||
|
||||
WEBHOOK_SECRET = os.environ.get("WEBHOOK_SECRET", "").strip()
|
||||
if not WEBHOOK_SECRET:
|
||||
logger.warning("WEBHOOK_SECRET is not set. Webhook signature verification will fail.")
|
||||
|
||||
# Canonical links
|
||||
GITEA_BASE_URL = os.environ.get("GITEA_BASE_URL", "https://src.koozali.org").rstrip("/")
|
||||
GITEA_ORG = os.environ.get("GITEA_ORG", "smeserver").strip() or "smeserver"
|
||||
|
||||
# Bugzilla config
|
||||
BUGZILLA_BASE_URL = os.environ.get("BUGZILLA_BASE_URL", "https://bugs.koozali.org").rstrip("/")
|
||||
BUGZILLA_AUTH_MODE = os.environ.get("BUGZILLA_AUTH_MODE", "").strip().lower() # "api_key" or "basic" (or auto)
|
||||
BUGZILLA_API_KEY = os.environ.get("BUGZILLA_API_KEY", "").strip()
|
||||
BUGZILLA_USER = os.environ.get("BUGZILLA_USER", "").strip()
|
||||
BUGZILLA_PASSWORD = os.environ.get("BUGZILLA_PASSWORD", "").strip()
|
||||
|
||||
# REQUIRED fields
|
||||
BUGZILLA_PRODUCT = os.environ.get("BUGZILLA_PRODUCT", "").strip()
|
||||
BUGZILLA_VERSION = os.environ.get("BUGZILLA_VERSION", "").strip()
|
||||
|
||||
# Component default
|
||||
BUGZILLA_COMPONENT_DEFAULT = os.environ.get("BUGZILLA_COMPONENT_DEFAULT", "e-smith-*/smeserver-* packages").strip()
|
||||
BUGZILLA_COMPONENT_FALLBACK = os.environ.get("BUGZILLA_COMPONENT_FALLBACK", BUGZILLA_COMPONENT_DEFAULT).strip()
|
||||
|
||||
# Custom field settings
|
||||
CF_PACKAGE_FIELD = os.environ.get("BUGZILLA_CF_PACKAGE_FIELD", "cf_package").strip()
|
||||
CF_PACKAGE_FALLBACK = os.environ.get("BUGZILLA_CF_PACKAGE_FALLBACK", "---").strip()
|
||||
|
||||
# CC behavior
|
||||
BUGZILLA_CC_ENABLE = os.environ.get("BUGZILLA_CC_ENABLE", "true").strip().lower() == "true"
|
||||
BUGZILLA_CC_ALLOW_NOREPLY = os.environ.get("BUGZILLA_CC_ALLOW_NOREPLY", "false").strip().lower() == "true"
|
||||
BUGZILLA_CC_FALLBACK_COMMENT = os.environ.get("BUGZILLA_CC_FALLBACK_COMMENT", "true").strip().lower() == "true"
|
||||
AUTHOR_EMAIL_MARKER = os.environ.get("BUGZILLA_AUTHOR_EMAIL_MARKER", "[mirror-bot:author-email]").strip()
|
||||
|
||||
# Behavior toggles
|
||||
BUGZILLA_ATTACH_DIFF = os.environ.get("BUGZILLA_ATTACH_DIFF", "true").strip().lower() == "true"
|
||||
BUGZILLA_FAILURE_LABEL = os.environ.get("BUGZILLA_FAILURE_LABEL", "bugzilla-needed").strip()
|
||||
GITHUB_DRY_RUN = os.environ.get("GITHUB_DRY_RUN", "false").strip().lower() == "true"
|
||||
if GITHUB_DRY_RUN:
|
||||
logger.info("GITHUB_DRY_RUN is enabled. The server will not comment/close PRs.")
|
||||
|
||||
# SQLite for PR→Bug mapping
|
||||
STATE_PATH = os.environ.get("STATE_PATH", "./webhook_state.sqlite")
|
||||
|
||||
# ---------------- State store ----------------
|
||||
|
||||
class State:
|
||||
def __init__(self, path: str):
|
||||
self.conn = sqlite3.connect(path, check_same_thread=False)
|
||||
self._init()
|
||||
|
||||
def _init(self):
|
||||
c = self.conn.cursor()
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS pr_map (
|
||||
pr_key TEXT PRIMARY KEY,
|
||||
bug_id INTEGER NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
)""")
|
||||
self.conn.commit()
|
||||
|
||||
def get_bug(self, pr_key: str) -> Optional[int]:
|
||||
c = self.conn.cursor()
|
||||
c.execute("SELECT bug_id FROM pr_map WHERE pr_key=?", (pr_key,))
|
||||
row = c.fetchone()
|
||||
return row[0] if row else None
|
||||
|
||||
def set_bug(self, pr_key: str, bug_id: int):
|
||||
import datetime as dt
|
||||
from datetime import timezone
|
||||
now = dt.datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
|
||||
c = self.conn.cursor()
|
||||
c.execute("""
|
||||
INSERT INTO pr_map (pr_key, bug_id, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(pr_key) DO UPDATE SET bug_id=excluded.bug_id, updated_at=excluded.updated_at
|
||||
""", (pr_key, bug_id, now, now))
|
||||
self.conn.commit()
|
||||
|
||||
# ---------------- Bugzilla hybrid client ----------------
|
||||
|
||||
class BugzillaHybrid:
|
||||
def __init__(self):
|
||||
self.base = BUGZILLA_BASE_URL
|
||||
self.mode = None # "rest" or "jsonrpc"
|
||||
self.rest_base = None
|
||||
self.rpc_url = f"{self.base}/jsonrpc.cgi"
|
||||
self._token: Optional[str] = None # for basic via JSON-RPC
|
||||
self._detect_mode()
|
||||
if BUGZILLA_AUTH_MODE in ("api_key", "") and BUGZILLA_API_KEY:
|
||||
logger.info("Bugzilla auth: API key mode")
|
||||
elif BUGZILLA_AUTH_MODE == "basic" or (BUGZILLA_USER and BUGZILLA_PASSWORD):
|
||||
logger.info("Bugzilla auth: basic/login (JSON-RPC token) mode")
|
||||
else:
|
||||
logger.warning("Bugzilla auth NOT configured yet (set BUGZILLA_API_KEY or BUGZILLA_USER/BUGZILLA_PASSWORD).")
|
||||
|
||||
def _detect_mode(self):
|
||||
try:
|
||||
r = httpx.get(f"{self.base}/rest/version", timeout=10)
|
||||
if r.status_code == 200:
|
||||
self.mode = "rest"
|
||||
self.rest_base = f"{self.base}/rest"
|
||||
logger.info("Bugzilla REST detected at /rest")
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
r = httpx.get(f"{self.base}/rest.cgi/version", timeout=10)
|
||||
if r.status_code == 200:
|
||||
self.mode = "rest"
|
||||
self.rest_base = f"{self.base}/rest.cgi"
|
||||
logger.info("Bugzilla REST detected at /rest.cgi")
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
self.mode = "jsonrpc"
|
||||
logger.warning("Bugzilla REST not available; falling back to JSON-RPC")
|
||||
|
||||
# ---------- REST helpers ----------
|
||||
|
||||
def _rest_headers(self) -> Dict[str, str]:
|
||||
h = {"Accept": "application/json", "Content-Type": "application/json"}
|
||||
if BUGZILLA_API_KEY:
|
||||
h["X-BUGZILLA-API-KEY"] = BUGZILLA_API_KEY
|
||||
return h
|
||||
|
||||
def _rest_auth(self) -> Optional[Tuple[str, str]]:
|
||||
if BUGZILLA_AUTH_MODE == "basic" and BUGZILLA_USER and BUGZILLA_PASSWORD:
|
||||
return (BUGZILLA_USER, BUGZILLA_PASSWORD)
|
||||
return None
|
||||
|
||||
# ---------- JSON-RPC helpers ----------
|
||||
|
||||
def _rpc_call(self, method: str, params_obj: Dict[str, Any], req_id: int = 1) -> Dict[str, Any]:
|
||||
body = {"method": method, "params": [params_obj], "id": req_id}
|
||||
r = httpx.post(self.rpc_url, headers={"Content-Type": "application/json"}, json=body, timeout=60)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
if data.get("error"):
|
||||
err = data["error"]
|
||||
raise RuntimeError(f"Bugzilla RPC error {err.get('code')}: {err.get('message')}")
|
||||
return data.get("result", {})
|
||||
|
||||
def _rpc(self, method: str, params_obj: Dict[str, Any], req_id: int = 1) -> Dict[str, Any]:
|
||||
mode = BUGZILLA_AUTH_MODE
|
||||
if (mode in ("", "api_key") and BUGZILLA_API_KEY):
|
||||
params_obj = dict(params_obj, Bugzilla_api_key=BUGZILLA_API_KEY)
|
||||
elif (mode == "basic" or (BUGZILLA_USER and BUGZILLA_PASSWORD)):
|
||||
if not self._token:
|
||||
self._token = self._login_rpc()
|
||||
params_obj = dict(params_obj, Bugzilla_token=self._token)
|
||||
else:
|
||||
raise RuntimeError("Bugzilla auth not configured (set BUGZILLA_API_KEY or BUGZILLA_USER/BUGZILLA_PASSWORD)")
|
||||
return self._rpc_call(method, params_obj, req_id=req_id)
|
||||
|
||||
def _login_rpc(self) -> str:
|
||||
if not (BUGZILLA_USER and BUGZILLA_PASSWORD):
|
||||
raise RuntimeError("Bugzilla basic auth requires BUGZILLA_USER and BUGZILLA_PASSWORD")
|
||||
data = self._rpc_call("User.login", {"login": BUGZILLA_USER, "password": BUGZILLA_PASSWORD}, req_id=0)
|
||||
token = data.get("token")
|
||||
if not token:
|
||||
raise RuntimeError("Bugzilla login did not return a token")
|
||||
logger.info("Bugzilla JSON-RPC login succeeded")
|
||||
return token
|
||||
|
||||
# ---------- Public API ----------
|
||||
|
||||
def create_bug(self, summary: str, description: str, component: str) -> int:
|
||||
if self.mode == "rest":
|
||||
try:
|
||||
url = f"{self.rest_base}/bug"
|
||||
payload = {
|
||||
"product": BUGZILLA_PRODUCT,
|
||||
"component": component or BUGZILLA_COMPONENT_DEFAULT,
|
||||
"version": BUGZILLA_VERSION,
|
||||
"summary": summary,
|
||||
"description": description,
|
||||
}
|
||||
r = httpx.post(url, headers=self._rest_headers(), auth=self._rest_auth(), json=payload, timeout=60)
|
||||
if r.status_code in (404, 405):
|
||||
raise httpx.HTTPStatusError("REST create not available", request=r.request, response=r)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
bug_id = data.get("id") or (data.get("bugs") and data["bugs"][0]["id"])
|
||||
if not bug_id:
|
||||
raise RuntimeError(f"REST create result missing id: {data}")
|
||||
return int(bug_id)
|
||||
except Exception as e:
|
||||
logger.warning(f"Bugzilla REST create failed, switching to JSON-RPC: {e}")
|
||||
self.mode = "jsonrpc"
|
||||
params = {
|
||||
"product": BUGZILLA_PRODUCT,
|
||||
"component": component or BUGZILLA_COMPONENT_DEFAULT,
|
||||
"version": BUGZILLA_VERSION,
|
||||
"summary": summary,
|
||||
"description": description,
|
||||
}
|
||||
res = self._rpc("Bug.create", params, req_id=1)
|
||||
bug_id = res.get("id") or (res.get("bugs") and res["bugs"][0]["id"])
|
||||
if not bug_id:
|
||||
raise RuntimeError(f"RPC create result missing id: {res}")
|
||||
return int(bug_id)
|
||||
|
||||
def add_attachment(self, bug_id: int, filename: str, summary: str, content_bytes: bytes):
|
||||
if self.mode == "rest":
|
||||
try:
|
||||
url = f"{self.rest_base}/bug/{bug_id}/attachment"
|
||||
payload = {
|
||||
"ids": [bug_id],
|
||||
"data": base64.b64encode(content_bytes).decode("ascii"),
|
||||
"file_name": filename,
|
||||
"summary": summary,
|
||||
"content_type": "text/x-patch",
|
||||
"is_patch": True,
|
||||
}
|
||||
r = httpx.post(url, headers=self._rest_headers(), auth=self._rest_auth(), json=payload, timeout=120)
|
||||
if r.status_code in (404, 405):
|
||||
raise httpx.HTTPStatusError("REST attachment not available", request=r.request, response=r)
|
||||
r.raise_for_status()
|
||||
return
|
||||
except Exception as e:
|
||||
logger.warning(f"Bugzilla REST add_attachment failed, switching to JSON-RPC: {e}")
|
||||
self.mode = "jsonrpc"
|
||||
params = {
|
||||
"ids": [bug_id],
|
||||
"data": base64.b64encode(content_bytes).decode("ascii"),
|
||||
"file_name": filename,
|
||||
"summary": summary,
|
||||
"content_type": "text/x-patch",
|
||||
"is_patch": True,
|
||||
}
|
||||
self._rpc("Bug.add_attachment", params, req_id=3)
|
||||
|
||||
def add_comment(self, bug_id: int, comment: str):
|
||||
if self.mode == "rest":
|
||||
try:
|
||||
url = f"{self.rest_base}/bug/{bug_id}/comment"
|
||||
payload = {"comment": comment}
|
||||
r = httpx.post(url, headers=self._rest_headers(), auth=self._rest_auth(), json=payload, timeout=60)
|
||||
if r.status_code in (404, 405):
|
||||
raise httpx.HTTPStatusError("REST add_comment not available", request=r.request, response=r)
|
||||
r.raise_for_status()
|
||||
return
|
||||
except Exception as e:
|
||||
logger.warning(f"Bugzilla REST add_comment failed, switching to JSON-RPC: {e}")
|
||||
self.mode = "jsonrpc"
|
||||
self._rpc("Bug.add_comment", {"id": bug_id, "comment": comment}, req_id=2)
|
||||
|
||||
def update_bug_fields(self, bug_id: int, fields: Dict[str, Any]):
|
||||
if self.mode == "rest":
|
||||
try:
|
||||
url = f"{self.rest_base}/bug/{bug_id}"
|
||||
r = httpx.put(url, headers=self._rest_headers(), auth=self._rest_auth(), json=fields, timeout=60)
|
||||
if r.status_code in (404, 405):
|
||||
raise httpx.HTTPStatusError("REST update not available", request=r.request, response=r)
|
||||
r.raise_for_status()
|
||||
return
|
||||
except Exception as e:
|
||||
logger.warning(f"Bugzilla REST update failed, switching to JSON-RPC: {e}")
|
||||
self.mode = "jsonrpc"
|
||||
params = {"ids": [bug_id]}
|
||||
params.update(fields)
|
||||
self._rpc("Bug.update", params, req_id=5)
|
||||
|
||||
def add_cc(self, bug_id: int, emails: List[str]):
|
||||
if not emails:
|
||||
return
|
||||
if self.mode == "rest":
|
||||
try:
|
||||
url = f"{self.rest_base}/bug/{bug_id}"
|
||||
payload = {"cc": {"add": emails}}
|
||||
r = httpx.put(url, headers=self._rest_headers(), auth=self._rest_auth(), json=payload, timeout=30)
|
||||
if r.status_code in (404, 405):
|
||||
raise httpx.HTTPStatusError("REST update not available", request=r.request, response=r)
|
||||
r.raise_for_status()
|
||||
return
|
||||
except Exception as e:
|
||||
logger.warning(f"Bugzilla REST add_cc failed, switching to JSON-RPC: {e}")
|
||||
self.mode = "jsonrpc"
|
||||
params = {"ids": [bug_id], "cc": {"add": emails}}
|
||||
self._rpc("Bug.update", params, req_id=6)
|
||||
|
||||
def list_comments(self, bug_id: int) -> List[str]:
|
||||
texts: List[str] = []
|
||||
if self.mode == "rest":
|
||||
try:
|
||||
url = f"{self.rest_base}/bug/{bug_id}/comment"
|
||||
r = httpx.get(url, headers=self._rest_headers(), auth=self._rest_auth(), timeout=30)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
bugs = data.get("bugs") or {}
|
||||
key = str(bug_id)
|
||||
if key in bugs:
|
||||
for c in (bugs[key].get("comments") or []):
|
||||
txt = c.get("text")
|
||||
if isinstance(txt, str):
|
||||
texts.append(txt)
|
||||
return texts
|
||||
except Exception as e:
|
||||
logger.warning(f"Bugzilla REST list_comments failed, switching to JSON-RPC: {e}")
|
||||
self.mode = "jsonrpc"
|
||||
# JSON-RPC
|
||||
res = self._rpc("Bug.comments", {"ids": [bug_id]}, req_id=7)
|
||||
bugs = res.get("bugs") or {}
|
||||
key = str(bug_id)
|
||||
if key in bugs:
|
||||
for c in (bugs[key].get("comments") or []):
|
||||
txt = c.get("text")
|
||||
if isinstance(txt, str):
|
||||
texts.append(txt)
|
||||
return texts
|
||||
|
||||
def add_or_update_author_email_note(self, bug_id: int, email: str):
|
||||
"""Post a marker comment with the author email if not already present."""
|
||||
try:
|
||||
existing = self.list_comments(bug_id)
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not list comments for bug {bug_id}: {e}")
|
||||
existing = []
|
||||
marker_line = f"{AUTHOR_EMAIL_MARKER} PR author email could not be added to CC (not registered): {email}"
|
||||
# Idempotent: if an existing marker has this exact email, do nothing
|
||||
for text in existing:
|
||||
if AUTHOR_EMAIL_MARKER in text and email in text:
|
||||
return
|
||||
# Otherwise add a new note
|
||||
self.add_comment(bug_id, marker_line)
|
||||
|
||||
# ---------------- GitHub client (PyGithub) ----------------
|
||||
|
||||
gh = Github(auth=Auth.Token(GITHUB_TOKEN)) if GITHUB_TOKEN else Github()
|
||||
state = State(STATE_PATH)
|
||||
bz = BugzillaHybrid()
|
||||
app = FastAPI()
|
||||
|
||||
# ---------------- Helpers ----------------
|
||||
|
||||
def verify_signature(secret: str, body: bytes, signature: str):
|
||||
if not signature:
|
||||
raise HTTPException(status_code=401, detail="Missing signature")
|
||||
expected = "sha256=" + hmac.new(secret.encode("utf-8"), body, hashlib.sha256).hexdigest()
|
||||
if not hmac.compare_digest(expected, signature):
|
||||
raise HTTPException(status_code=401, detail="Invalid signature")
|
||||
|
||||
def pr_comment_success(gitea_repo_url: str, bug_id: int) -> str:
|
||||
return (
|
||||
"Thanks for the contribution!\n\n"
|
||||
"This repository is a read-only mirror of the canonical repo on Gitea:\n"
|
||||
f"- Canonical: {gitea_repo_url}\n"
|
||||
f"- Please file and discuss changes in Bugzilla: {BUGZILLA_BASE_URL}\n\n"
|
||||
f"We created Bug {bug_id} to track this proposal:\n"
|
||||
f"- {BUGZILLA_BASE_URL}/show_bug.cgi?id={bug_id}\n\n"
|
||||
"This pull request will be closed here. Further pushes to this PR branch will be mirrored as updated attachments on the Bug.\n"
|
||||
)
|
||||
|
||||
def pr_comment_failure(gitea_repo_url: str, repo: str, pr_url: str, target_branch: str) -> str:
|
||||
return (
|
||||
"Thanks for the contribution!\n\n"
|
||||
"This repository is a read-only mirror of the canonical repo on Gitea:\n"
|
||||
f"- Canonical: {gitea_repo_url}\n\n"
|
||||
"We were unable to create a Bugzilla ticket automatically at this time.\n"
|
||||
f"Please open a bug at {BUGZILLA_BASE_URL} (Product: {BUGZILLA_PRODUCT}, Version: {BUGZILLA_VERSION}, Component: {BUGZILLA_COMPONENT_DEFAULT}) and include:\n"
|
||||
f"- GitHub PR: {pr_url}\n"
|
||||
f"- Target branch: {target_branch}\n"
|
||||
"- Summary and rationale for the change\n\n"
|
||||
"This pull request will remain open for now. Once a Bugzilla ticket exists, our maintainers will reference it here and proceed with review on Bugzilla.\n"
|
||||
)
|
||||
|
||||
def fetch_pr_patch(owner: str, repo: str, pr_num: int) -> bytes:
|
||||
url = f"https://api.github.com/repos/{owner}/{repo}/pulls/{pr_num}"
|
||||
headers = {"Accept": "application/vnd.github.v3.patch"}
|
||||
if GITHUB_TOKEN:
|
||||
headers["Authorization"] = f"token {GITHUB_TOKEN}"
|
||||
r = httpx.get(url, headers=headers, timeout=120)
|
||||
r.raise_for_status()
|
||||
return r.content
|
||||
|
||||
def derive_pr_author_email(owner: str, repo: str, pr_num: int, head_sha: str) -> Optional[str]:
|
||||
try:
|
||||
url = f"https://api.github.com/repos/{owner}/{repo}/commits/{head_sha}"
|
||||
headers = {"Accept": "application/vnd.github+json"}
|
||||
if GITHUB_TOKEN:
|
||||
headers["Authorization"] = f"token {GITHUB_TOKEN}"
|
||||
r = httpx.get(url, headers=headers, timeout=20)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
email = (data.get("commit") or {}).get("author", {}).get("email")
|
||||
if email:
|
||||
return email
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
url = f"https://api.github.com/repos/{owner}/{repo}/pulls/{pr_num}/commits"
|
||||
headers = {"Accept": "application/vnd.github+json"}
|
||||
if GITHUB_TOKEN:
|
||||
headers["Authorization"] = f"token {GITHUB_TOKEN}"
|
||||
r = httpx.get(url, headers=headers, timeout=20)
|
||||
if r.status_code == 200:
|
||||
commits = r.json()
|
||||
if commits:
|
||||
email = (commits[0].get("commit") or {}).get("author", {}).get("email")
|
||||
if email:
|
||||
return email
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
patch = fetch_pr_patch(owner, repo, pr_num).decode("utf-8", "ignore")
|
||||
for line in patch.splitlines():
|
||||
if line.startswith("From: ") and "<" in line and ">" in line:
|
||||
cand = line[line.find("<")+1:line.find(">", line.find("<")+1)].strip()
|
||||
if "@" in cand:
|
||||
return cand
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
# ---------------- Routes ----------------
|
||||
|
||||
@app.get("/healthz")
|
||||
async def healthz():
|
||||
gh_status = {"ok": False}
|
||||
bz_status = {"ok": False}
|
||||
|
||||
# GitHub quick check: rate limit endpoint
|
||||
try:
|
||||
gh_headers = {"Accept": "application/vnd.github+json"}
|
||||
if GITHUB_TOKEN:
|
||||
gh_headers["Authorization"] = f"token {GITHUB_TOKEN}"
|
||||
r = httpx.get("https://api.github.com/rate_limit", headers=gh_headers, timeout=5)
|
||||
gh_status["http_status"] = r.status_code
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
core = (data.get("resources") or {}).get("core") or {}
|
||||
gh_status.update({
|
||||
"remaining": core.get("remaining"),
|
||||
"reset": core.get("reset"),
|
||||
})
|
||||
gh_status["ok"] = True
|
||||
else:
|
||||
gh_status["error"] = r.text[:200]
|
||||
except Exception as e:
|
||||
gh_status["error"] = str(e)[:200]
|
||||
|
||||
# Bugzilla quick check: REST /version if available, else JSON-RPC Bugzilla.version
|
||||
try:
|
||||
if getattr(bz, "mode", None) == "rest" and getattr(bz, "rest_base", None):
|
||||
r2 = httpx.get(f"{bz.rest_base}/version",
|
||||
headers=bz._rest_headers(),
|
||||
auth=bz._rest_auth(),
|
||||
timeout=5)
|
||||
bz_status["http_status"] = r2.status_code
|
||||
if r2.status_code == 200:
|
||||
bz_status["version"] = (r2.json() or {}).get("version")
|
||||
bz_status["ok"] = True
|
||||
else:
|
||||
bz_status["error"] = r2.text[:200]
|
||||
else:
|
||||
payload = {"method": "Bugzilla.version", "params": [{}], "id": 99}
|
||||
# Include API key if configured (not strictly required for version)
|
||||
if BUGZILLA_API_KEY:
|
||||
payload["params"][0]["Bugzilla_api_key"] = BUGZILLA_API_KEY
|
||||
r2 = httpx.post(bz.rpc_url,
|
||||
headers={"Content-Type": "application/json"},
|
||||
json=payload,
|
||||
timeout=5)
|
||||
bz_status["http_status"] = r2.status_code
|
||||
if r2.status_code == 200:
|
||||
data = r2.json()
|
||||
if not data.get("error"):
|
||||
bz_status["version"] = (data.get("result") or {}).get("version")
|
||||
bz_status["ok"] = True
|
||||
else:
|
||||
bz_status["error"] = str(data["error"])[:200]
|
||||
else:
|
||||
bz_status["error"] = r2.text[:200]
|
||||
except Exception as e:
|
||||
bz_status["error"] = str(e)[:200]
|
||||
|
||||
overall_ok = bool(gh_status.get("ok") and bz_status.get("ok"))
|
||||
status_code = 200 if overall_ok else 503
|
||||
return JSONResponse({"ok": overall_ok, "github": gh_status, "bugzilla": bz_status},
|
||||
status_code=status_code)
|
||||
|
||||
@app.post("/webhook/github")
|
||||
async def github_webhook(
|
||||
request: Request,
|
||||
x_hub_signature_256: str = Header(None),
|
||||
x_github_event: str = Header(None),
|
||||
):
|
||||
if not BUGZILLA_PRODUCT or not BUGZILLA_VERSION:
|
||||
raise HTTPException(status_code=500, detail="BUGZILLA_PRODUCT and BUGZILLA_VERSION must be set")
|
||||
|
||||
body = await request.body()
|
||||
verify_signature(WEBHOOK_SECRET, body, x_hub_signature_256)
|
||||
|
||||
try:
|
||||
payload = json.loads(body.decode("utf-8"))
|
||||
except Exception:
|
||||
raise HTTPException(status_code=400, detail="Invalid JSON")
|
||||
|
||||
if x_github_event != "pull_request":
|
||||
return JSONResponse({"status": "ignored", "event": x_github_event})
|
||||
|
||||
action = payload.get("action")
|
||||
if action not in ("opened", "reopened", "synchronize", "ready_for_review"):
|
||||
return JSONResponse({"status": "ignored", "action": action})
|
||||
|
||||
repo_full = payload["repository"]["full_name"]
|
||||
owner = payload["repository"]["owner"]["login"]
|
||||
repo = payload["repository"]["name"]
|
||||
pr = payload["pull_request"]
|
||||
pr_num = pr["number"]
|
||||
pr_url = pr["html_url"]
|
||||
pr_title = pr.get("title") or ""
|
||||
pr_body = pr.get("body") or ""
|
||||
base = pr["base"]
|
||||
head = pr["head"]
|
||||
target_branch = base["ref"]
|
||||
head_sha = head["sha"][:7]
|
||||
|
||||
gitea_repo_url = f"{GITEA_BASE_URL}/{GITEA_ORG}/{repo}"
|
||||
pr_key = f"{repo_full}#{pr_num}"
|
||||
bug_id = state.get_bug(pr_key)
|
||||
|
||||
gh_repo = None
|
||||
if not GITHUB_DRY_RUN:
|
||||
try:
|
||||
gh_repo = gh.get_repo(repo_full)
|
||||
except Exception as ge:
|
||||
logger.warning(f"Could not access GitHub repo {repo_full}: {ge}")
|
||||
|
||||
if bug_id is None and action in ("opened", "reopened", "ready_for_review", "synchronize"):
|
||||
summary = f"[GH PR #{pr_num}] {GITEA_ORG}/{repo}: {pr_title}"
|
||||
description = (
|
||||
"Source\n"
|
||||
f"- Canonical repo (Gitea): {gitea_repo_url}\n"
|
||||
f"- GitHub mirror PR: {pr_url}\n\n"
|
||||
"Project policy\n"
|
||||
"This GitHub repository is a read-only mirror. Reviews and decisions happen in Bugzilla.\n\n"
|
||||
"Submitter’s notes\n"
|
||||
f"{pr_body}\n"
|
||||
)
|
||||
try:
|
||||
bug_id = bz.create_bug(summary, description, component=BUGZILLA_COMPONENT_DEFAULT)
|
||||
state.set_bug(pr_key, bug_id)
|
||||
logger.info(f"Created Bugzilla bug {bug_id} for {pr_key}")
|
||||
# Set cf_package to repo, fallback to '---'
|
||||
try:
|
||||
bz.update_bug_fields(bug_id, {CF_PACKAGE_FIELD: repo})
|
||||
logger.info(f"Set {CF_PACKAGE_FIELD}={repo} on bug {bug_id}")
|
||||
except Exception as e_cf:
|
||||
logger.warning(f"Failed to set {CF_PACKAGE_FIELD} to '{repo}' on bug {bug_id}: {e_cf}; falling back to '{CF_PACKAGE_FALLBACK}'")
|
||||
with contextlib.suppress(Exception):
|
||||
bz.update_bug_fields(bug_id, {CF_PACKAGE_FIELD: CF_PACKAGE_FALLBACK})
|
||||
logger.info(f"Set {CF_PACKAGE_FIELD}={CF_PACKAGE_FALLBACK} on bug {bug_id}")
|
||||
# Add PR author to CC (or comment fallback)
|
||||
if BUGZILLA_CC_ENABLE:
|
||||
email = derive_pr_author_email(owner, repo, pr_num, head_sha)
|
||||
if email:
|
||||
is_noreply = email.endswith("@users.noreply.github.com")
|
||||
if not is_noreply or BUGZILLA_CC_ALLOW_NOREPLY:
|
||||
try:
|
||||
bz.add_cc(bug_id, [email])
|
||||
logger.info(f"Added CC {email} to bug {bug_id}")
|
||||
except Exception as e_cc:
|
||||
logger.warning(f"Failed to add CC {email} to bug {bug_id}: {e_cc}")
|
||||
if BUGZILLA_CC_FALLBACK_COMMENT:
|
||||
with contextlib.suppress(Exception):
|
||||
bz.add_or_update_author_email_note(bug_id, email)
|
||||
else:
|
||||
logger.info(f"Skipping noreply CC {email} (set BUGZILLA_CC_ALLOW_NOREPLY=true to allow)")
|
||||
else:
|
||||
logger.info("Could not derive PR author email; CC not added")
|
||||
except Exception as e:
|
||||
logger.error(f"Bugzilla create failed for {pr_key}: {e}")
|
||||
if not GITHUB_DRY_RUN and gh_repo is not None:
|
||||
try:
|
||||
gh_repo.get_pull(pr_num).create_issue_comment(pr_comment_failure(gitea_repo_url, repo, pr_url, target_branch))
|
||||
if BUGZILLA_FAILURE_LABEL:
|
||||
with contextlib.suppress(Exception):
|
||||
gh_repo.create_label(BUGZILLA_FAILURE_LABEL, "ededed")
|
||||
with contextlib.suppress(Exception):
|
||||
gh_repo.get_issue(pr_num).add_to_labels(BUGZILLA_FAILURE_LABEL)
|
||||
except Exception as ge:
|
||||
logger.warning(f"Could not post failure comment on PR #{pr_num}: {ge}")
|
||||
else:
|
||||
logger.info(f"[GITHUB_DRY_RUN] Would comment failure on PR #{pr_num}, label={BUGZILLA_FAILURE_LABEL}")
|
||||
return JSONResponse({"status": "bugzilla_failed", "action": action})
|
||||
|
||||
if BUGZILLA_ATTACH_DIFF:
|
||||
try:
|
||||
patch = fetch_pr_patch(owner, repo, pr_num)
|
||||
bz.add_attachment(
|
||||
bug_id=bug_id,
|
||||
filename=f"PR-{pr_num}-{head_sha}.patch",
|
||||
summary=f"Patch for PR #{pr_num} ({head_sha})",
|
||||
content_bytes=patch
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"Attach patch failed for bug {bug_id}: {e}")
|
||||
|
||||
comment = pr_comment_success(gitea_repo_url, bug_id)
|
||||
if not GITHUB_DRY_RUN and gh_repo is not None:
|
||||
try:
|
||||
pr_obj = gh_repo.get_pull(pr_num)
|
||||
pr_obj.create_issue_comment(comment)
|
||||
if pr_obj.state != "closed":
|
||||
pr_obj.edit(state="closed")
|
||||
except Exception as ge:
|
||||
logger.warning(f"Could not comment/close PR #{pr_num}: {ge}")
|
||||
else:
|
||||
logger.info(f"[GITHUB_DRY_RUN] Would post success comment and close PR #{pr_num}")
|
||||
return JSONResponse({"status": "ok", "bug_id": bug_id})
|
||||
|
||||
elif bug_id is not None and action == "synchronize":
|
||||
try:
|
||||
if BUGZILLA_ATTACH_DIFF:
|
||||
patch = fetch_pr_patch(owner, repo, pr_num)
|
||||
bz.add_attachment(
|
||||
bug_id=bug_id,
|
||||
filename=f"PR-{pr_num}-{head_sha}.patch",
|
||||
summary=f"Updated patch for PR #{pr_num} ({head_sha})",
|
||||
content_bytes=patch
|
||||
)
|
||||
if not GITHUB_DRY_RUN and gh_repo is not None:
|
||||
try:
|
||||
pr_obj = gh_repo.get_pull(pr_num)
|
||||
if pr_obj.state != "closed":
|
||||
pr_obj.edit(state="closed")
|
||||
except Exception as ge:
|
||||
logger.warning(f"Could not ensure PR #{pr_num} closed: {ge}")
|
||||
else:
|
||||
logger.info(f"[GITHUB_DRY_RUN] Would ensure PR #{pr_num} closed")
|
||||
return JSONResponse({"status": "ok", "bug_id": bug_id})
|
||||
except Exception as e:
|
||||
logger.error(f"Attach update failed for bug {bug_id}: {e}")
|
||||
if not GITHUB_DRY_RUN and gh_repo is not None:
|
||||
with contextlib.suppress(Exception):
|
||||
pr_obj = gh_repo.get_pull(pr_num)
|
||||
if pr_obj.state != "closed":
|
||||
pr_obj.edit(state="closed")
|
||||
else:
|
||||
logger.info(f"[GITHUB_DRY_RUN] Would ensure PR #{pr_num} closed (after attach failure)")
|
||||
return JSONResponse({"status": "attach_failed", "bug_id": bug_id})
|
||||
|
||||
return JSONResponse({"status": "noop"})
|
||||
Reference in New Issue
Block a user