Compare commits

..

235 Commits

Author SHA1 Message Date
trevorb
ee7d51ff4b update to new tag format 2025-10-09 12:41:02 +11:00
b72a4b62c2 more test programs 2025-09-25 12:46:09 +02:00
588ba4698c Upload PR instructions for use in Wiki when job is done and it goes public 2025-09-25 12:45:00 +02:00
cdee67e203 Update webhook server code and requirements files 2025-09-25 12:43:28 +02:00
9e577a1abe Upload Enhanced webhook endpoint with gitea PR creation - not fully tested 2025-09-25 12:41:31 +02:00
881c77c383 Add webhook endpoint test programs 2025-09-25 12:40:25 +02:00
b3e200e9d6 Requirements for webhook_endpoint.py 2025-09-19 17:41:33 +02:00
7da658ec0f Latest version - 19Sept2025
As running on vps.bjsystems.co.uk accessible by: https://githubpr.bjsystems.co.uk

https://githubpr.bjsystems.co.uk/healthz
https://githubpr.bjsystems.co.uk/webhook/github
2025-09-19 17:40:15 +02:00
de4bf24f5b Name changed. 2025-09-18 07:23:05 +02:00
8a7c8ad75a After standalone Testing 2025-09-18 07:21:59 +02:00
69e6e0659f Initial upload - Untested.
Link between the Github repos and the bugzilla, runs as a web service, receives webhook on PR from github.
2025-09-17 07:17:29 +02:00
d2b8690c0a Add proper logging and fix deprecated time calls. 2025-09-16 17:15:51 +02:00
2147fdbb02 Requirements file for gitea2githubSync 2025-09-16 15:05:12 +02:00
761045bd62 Initial upload of gitea to github sync python3 program
Creates github repo ok, not yet fully tested
2025-09-16 14:58:42 +02:00
trevorb
50f193b2db fix README for git-retag.sh 2024-12-20 20:09:10 +11:00
e30641250e use awk and markdown for contribs 2024-10-27 15:44:50 +00:00
0c858eaba1 Add git-edit-readme.sh 2024-10-27 12:07:54 +00:00
c4f00b4328 Update Readme.md 2024-05-26 21:24:58 +02:00
f984ec736d Update Readme.md 2024-05-26 21:22:14 +02:00
454e474564 Add github-make-push-mirror.sh 2024-05-26 20:18:34 +01:00
Trevor Batley
8f06ffbed9 fix cpan bug link 2024-03-27 18:21:03 +11:00
Trevor Batley
c15231193b README take 5 2024-03-27 18:03:21 +11:00
Trevor Batley
bd51a307e8 README take 3README take 3 2024-03-27 17:34:16 +11:00
Trevor Batley
f948bbc974 fix Makefile 2024-03-27 16:57:44 +11:00
Trevor Batley
6fff2d19f5 fix bugs 2024-03-27 16:45:48 +11:00
Trevor Batley
fb6a44f132 fix lfs, Makefile, README.md and BuildRequires 2024-03-27 15:05:25 +11:00
Trevor Batley
c5800c3e14 Get tarball extension for lfs 2024-03-26 17:21:10 +11:00
Trevor Batley
1a4d5ade8f change name in generated Makefile 2024-03-26 16:38:45 +11:00
Trevor Batley
331c908cb8 add makefile and tag in getperl 2024-03-25 08:24:32 +11:00
TrevorB
c5d71a4da7 add git-getperl 2024-03-24 22:35:07 +11:00
Trevor Batley
452e84b2ca TAG to use _ instead of . 2024-03-24 10:29:15 +11:00
Trevor Batley
1e00424274 look for common in smeserver 2024-03-22 17:42:23 +11:00
e19bd34d0c revert f8e6992cea
revert Add in change to tar file name
2024-03-15 10:50:35 +01:00
f8e6992cea Add in change to tar file name 2024-03-14 20:06:45 +01:00
28d6cb1a44 Update 'README.md' 2024-03-12 21:43:12 +01:00
0ca87cfbee Update README with git-get-latest-tag.sh 2024-03-12 20:41:40 +00:00
13d705639c Add git-get-latest-tag.sh 2024-03-12 20:38:19 +00:00
Brian Read
c690004aca Add rpmspec test 2024-03-11 19:31:47 +00:00
Trevor Batley
a90599279b add clean option 2024-03-11 21:01:54 +11:00
Trevor Batley
9916c56721 fix for version release 2024-03-11 20:56:30 +11:00
Trevor Batley
5c4f74da8f version release 2024-03-11 09:18:16 +11:00
f7e6b20b25 Fix dot points under git-retag.sh 2024-02-16 01:11:43 +01:00
Trevor Batley
9fd4f2cce8 fix mirror=false 2023-11-20 11:43:02 +11:00
Trevor Batley
c8f81a0315 use gitea api instead of git for tag delete 2023-11-18 07:54:54 +11:00
Trevor Batley
0c53f9fae6 add git-retag.sh to README 2023-11-17 15:00:14 +11:00
Trevor Batley
ce14ed07fc fix version release 2023-11-17 14:49:55 +11:00
Trevor Batley
eaf957da50 delete ALL old tags 2023-11-17 12:40:43 +11:00
Trevor Batley
4ddb8de08e add release back into tag 2023-11-17 09:35:33 +11:00
c25fa1943a Fix OpenAI key 2023-08-21 08:21:03 +02:00
Trevor Batley
19efadfa1d move rename-e-smith to it's own repository 2023-07-24 09:21:32 +10:00
Trevor Batley
750bde5b38 typo again 2023-07-23 19:23:17 +10:00
Trevor Batley
de31b20e72 typo 2023-07-23 19:20:25 +10:00
Trevor Batley
c6e57c9475 add branch parameter 2023-07-23 17:28:12 +10:00
Trevor Batley
98eddc7b64 Added branch option 2023-07-23 15:17:45 +10:00
Brian Read
e2b9906429 Add in asseturls to options for git-list.. 2023-07-20 20:00:36 +01:00
Brian Read
99be082770 Alter foprmat for list and a small fix for make-release 2023-07-20 15:42:16 +01:00
029b3fe3cd Update README for update-release 2023-07-20 12:58:26 +02:00
Brian Read
70daf74b8d Add in update and delete release scripts 2023-07-20 11:55:03 +01:00
Brian Read
307a492847 Update list-all-ord-repos to include all releases 2023-07-19 13:20:02 +01:00
Brian Read
ee106a077c Take out early exit - left in by mistake! 2023-07-19 12:31:00 +01:00
Brian Read
fd798e83c3 Add release types to make-release 2023-07-19 12:22:50 +01:00
Brian Read
477ecb7c4d Add release type to make-release, add WIP list of repos
Update email address
2023-07-19 12:17:27 +01:00
6e9f8dddb9 Add comment re: scripts being in path 2023-07-18 07:10:38 +02:00
Brian Read
133cea8089 Add test for null release tag and exit if so 2023-07-17 10:27:17 +01:00
Trevor Batley
e966afb059 Delete reference to make-archive - no longer used 2023-07-14 14:15:58 +10:00
be872a008e Delete reference to make-archive - no longer in use. 2023-07-12 09:18:36 +02:00
Brian Read
b60d27a7fe Forgot SME in tag for release search API call 2023-07-10 11:54:02 +01:00
Brian Read
ff0eeb0fce Remove RELEASE from tag as reflects build system not system being built 2023-07-09 16:15:44 +01:00
5b30bee2a9 fix format for git-make-release.sh doc 2023-07-09 12:56:38 +02:00
Brian Read
89e71d95a5 Added git-make-release.sh 2023-07-09 11:52:15 +01:00
Brian Read
21a3a248b2 Add check for lua - needed for change-log 2023-07-05 13:56:36 +01:00
Brian Read
36616d567f Bring BogusDateBot check and call into line - remove /usr/bin 2023-07-05 13:48:37 +01:00
Brian Read
44432a300b Sort out parameter to make prep for DEBUG mode 2023-07-05 12:20:56 +01:00
Brian Read
11c8552978 Remove SILENT from make prep as it treats the -v as version 2023-07-04 06:50:43 -04:00
Brian Read
211c2ee576 Re-instate exit if change-log or bogus data not found 2023-07-03 11:00:19 -04:00
Trevor Batley
27b59de7aa remove e-smith-openssh special fix 2023-06-25 11:04:14 +10:00
Trevor Batley
afe2c69d3e mistype 2023-06-24 17:06:42 +10:00
Trevor Batley
5cf5ed1278 wap Requires from e-smith to e-smith-base 2023-06-24 16:54:17 +10:00
Trevor Batley
38fa8363e5 change tar.gz or tgz to tar.xz 2023-06-24 16:39:53 +10:00
Trevor Batley
b7188cbf4b Updated comments 2023-06-21 16:53:28 +10:00
Trevor Batley
7a7a68753a fix e-smith-lib sed 2023-06-15 15:53:29 +10:00
Trevor Batley
6d940ffda8 moved package specific to cvs2git 2023-06-15 15:47:06 +10:00
Trevor Batley
988513d86b package specific changes from make prep 2023-06-15 15:46:13 +10:00
Trevor Batley
bf8e39046a tell sed which file 2023-06-15 15:09:57 +10:00
Trevor Batley
913c24a33f delete the setup lines for Source1 & 2 2023-06-15 15:04:11 +10:00
Trevor Batley
f50cfc1ca7 add after not before 2023-06-15 14:45:23 +10:00
Trevor Batley
3094498fc6 square brackets 2023-06-15 14:29:36 +10:00
Trevor Batley
a0fe5dd71d add package specific fixes 2023-06-15 14:24:59 +10:00
Trevor Batley
999c22b420 show return code on non-zero exit 2023-06-15 10:19:59 +10:00
Trevor Batley
3f8e6f31ae remove trailing - in sed 2023-06-14 17:09:01 +10:00
Trevor Batley
1333f1a651 sed Name as well as defne name 2023-06-14 17:02:03 +10:00
Trevor Batley
8f8632e65e fix archivefilename 2023-06-14 16:48:14 +10:00
Trevor Batley
e3f3040073 get quotes right 2023-06-13 16:58:04 +10:00
Trevor Batley
a99d2a59c1 change e-smith to smeserver in archivefilename 2023-06-13 16:53:39 +10:00
Trevor Batley
ea5551e41f check format of archivefilename 2023-06-13 16:39:10 +10:00
Trevor Batley
15899ef0c7 lots more debug 2023-06-13 10:12:49 +10:00
Trevor Batley
9c4d268e3d add in extra parms 2023-06-13 09:37:45 +10:00
94f7e151c0 Take out "GITFiles" in mkdir as the WORKDIR var includes it already. 2023-06-09 07:12:53 +02:00
4671bb0abd Remove "GITFiles" in mkdir as already specified in the $WORKDIR var 2023-06-09 07:06:44 +02:00
Trevor Batley
bb5278ebd5 hold off on requires changes for now 2023-06-07 10:38:12 +10:00
Trevor Batley
9c827793e0 correct return code processing 2023-06-06 20:40:43 +10:00
Trevor Batley
5207676ada cant rm whilst in the directory... 2023-06-06 20:19:09 +10:00
Trevor Batley
5861b6af76 show output of failed script 2023-06-06 20:08:26 +10:00
Trevor Batley
7c125e18d1 QUIET a different way 2023-06-06 19:39:40 +10:00
Trevor Batley
6237cbec79 correct order of params in README.md 2023-06-06 19:36:22 +10:00
Trevor Batley
d0242b29ce add clarity to error display 2023-06-06 19:34:10 +10:00
Trevor Batley
7eb6b5769e quieten a little 2023-06-06 19:31:48 +10:00
Trevor Batley
dc0ed1b79d correctly arrange $1=repo and $2=org in all places 2023-06-06 19:23:05 +10:00
Trevor Batley
96094332ef remove spurious -q 2023-06-06 16:57:14 +10:00
Trevor Batley
1e40fa679c fix paramlist missing 2023-06-06 16:46:48 +10:00
Trevor Batley
2b60851ea3 encapsulate params 2023-06-06 12:26:36 +10:00
Trevor Batley
51ecfe7ee1 delete spurious quotes 2023-06-06 12:18:51 +10:00
Trevor Batley
f0a02bc746 define array 2023-06-06 12:14:00 +10:00
Trevor Batley
ff91ef36e3 remove extra displays 2023-06-06 12:12:27 +10:00
Trevor Batley
09f76ab8ab param vs file 2023-06-06 11:51:56 +10:00
Trevor Batley
d05df71e5c fix sppend 2023-06-06 11:49:16 +10:00
Trevor Batley
0c2b8da54f parse input fiile to array before provcessing 2023-06-06 11:45:25 +10:00
Trevor Batley
f2b2c021f8 add in debug param 2023-06-05 16:18:06 +10:00
Trevor Batley
72625870bf remove git-migrate-org.sh script 2023-06-05 15:43:44 +10:00
Trevor Batley
485c2090a1 add git-transfer-repo.sh to README.md 2023-06-05 15:41:58 +10:00
Trevor Batley
15ffd74a3e add git-transfer-repo.sh script 2023-06-05 15:31:16 +10:00
Trevor Batley
ef23cc5f9a capture fail of migrate 2023-06-05 14:54:51 +10:00
Trevor Batley
c9e3f1782c more debug statements 2023-06-05 14:04:19 +10:00
Trevor Batley
de4a821af5 check code not data 2023-06-05 11:03:12 +10:00
Trevor Batley
32268cd2a9 error message re: unable to delete 2023-06-05 10:58:40 +10:00
Trevor Batley
9fd1578a7e delete the target not the source 2023-06-05 10:45:49 +10:00
Trevor Batley
75aa177430 added in delete of pkg on transfer 2023-06-05 10:41:39 +10:00
Trevor Batley
1116647ec2 check code not data 2023-06-05 10:18:11 +10:00
Trevor Batley
9cd1d56a72 undo in-situ - must be owner 2023-06-05 09:56:26 +10:00
Trevor Batley
96f7295f96 do it all in the same org 2023-06-05 09:42:48 +10:00
Trevor Batley
901042b562 GITEAHOST not GITEAURL 2023-06-05 09:31:37 +10:00
Trevor Batley
2036ae59f4 add optional transfer back to source org 2023-06-05 09:21:54 +10:00
Trevor Batley
178d0f37ab remove forked comment on success 2023-06-05 08:57:13 +10:00
Trevor Batley
a7b3cda711 add back in update of external issues and wiki 2023-06-05 08:52:52 +10:00
Trevor Batley
ce96666422 add back in bug & wiki 2023-06-05 08:44:51 +10:00
Trevor Batley
9b86646411 add in cloneurl 2023-06-04 21:56:51 +10:00
Trevor Batley
6f09d7a865 variable names wrong 2023-06-04 21:43:34 +10:00
Trevor Batley
80d42edbc1 FIIK 2023-06-04 18:04:38 +10:00
Trevor Batley
80f76cf8ac ? accesstokens ? 2023-06-04 17:50:56 +10:00
Trevor Batley
1aeb5b4c36 mixed up source & target 2023-06-04 17:39:24 +10:00
Trevor Batley
b497a00693 change to migrate rather than fork 2023-06-04 17:00:24 +10:00
Trevor Batley
277035cf55 tidy up parameter descriptions and add example 2023-06-04 10:44:39 +10:00
Trevor Batley
61f97c908e add additional params 2023-06-04 09:08:49 +10:00
Trevor Batley
6b45e5f846 missed review option for parse-list.sh 2023-06-03 17:09:24 +10:00
Trevor Batley
7cde1aaeff escape < and > 2023-06-03 17:07:31 +10:00
Trevor Batley
96e105213e escape < and > 2023-06-03 17:06:40 +10:00
Trevor Batley
d0ceacf5ef update parse-list.sh options 2023-06-03 17:04:49 +10:00
Trevor Batley
db62df1090 silence curl output 2023-06-03 16:57:10 +10:00
Trevor Batley
51d864512f add local to extraparams if set 2023-06-03 16:54:12 +10:00
Trevor Batley
ec984efd3d use $1 2023-06-03 16:51:39 +10:00
Trevor Batley
5c065162dd too many " 2023-06-03 16:46:27 +10:00
Trevor Batley
255cce967a add in smegit/config processing 2023-06-03 16:42:01 +10:00
Trevor Batley
7fb53cc776 add org= option 2023-06-03 16:22:03 +10:00
Trevor Batley
a7eebc7ac7 use $SOURCEHOST 2023-06-03 15:17:31 +10:00
Trevor Batley
aab64d1ed7 remove quotes with jq -r 2023-06-03 14:24:26 +10:00
Trevor Batley
2822c44f8e correct continiuation character 2023-06-03 14:18:21 +10:00
Trevor Batley
3b2ab5189a typo 2023-06-03 13:36:24 +10:00
Trevor Batley
240928b74b direct extract or wikiurl from curl 2023-06-03 13:29:22 +10:00
Trevor Batley
d05be5fa35 spurious , 2023-06-03 12:23:25 +10:00
Trevor Batley
840b9e9057 get wiki link from source repo and use it 2023-06-03 12:11:10 +10:00
Trevor Batley
5199f9ea5e remove suppress 2023-06-03 09:09:26 +10:00
456cee3067 Typos. 2023-06-02 15:36:24 +02:00
9cbece1ab8 Update README with git-post-create-repo.sh details 2023-06-02 15:34:55 +02:00
b97d611c79 Merge branch 'master' of https://src.koozali.org/smedev/smeserver-gitutils
ok
2023-06-02 14:27:53 +01:00
56969eff40 Add post create frm template script 2023-06-02 14:26:42 +01:00
Trevor Batley
040abb21e0 remove suppress from git clone 2023-06-02 21:28:05 +10:00
Trevor Batley
ad89dc6c4c fix suppress 2023-06-02 21:25:13 +10:00
Trevor Batley
00b2b13244 more quiet bits 2023-06-02 21:13:39 +10:00
Trevor Batley
feda70a9b2 revert curl output suppression on create 2023-06-02 21:02:55 +10:00
Trevor Batley
95e4647899 added space before ] 2023-06-02 20:58:52 +10:00
Trevor Batley
65e19bcdda add quiet or suppress 2023-06-02 20:55:28 +10:00
Trevor Batley
4e00e4676b fix http_code return from curl 2023-06-02 17:31:17 +10:00
Trevor Batley
3c94831315 refactor where Repository deleted 2023-06-02 17:02:59 +10:00
Trevor Batley
51551534f1 add 4-04 check on repo delete 2023-06-02 16:27:46 +10:00
08f624fd4d add in all optional parameters 2023-06-02 03:59:49 +02:00
Trevor Batley
0f1f9c72ec add parse-list.sh to README.md 2023-06-02 11:47:11 +10:00
Trevor Batley
6f67751985 add parse-list.sh script 2023-06-02 11:38:02 +10:00
Trevor Batley
76fbc34b5d suppress all output 2023-06-02 11:15:30 +10:00
Trevor Batley
e68b051f83 option for nooutput 2023-06-02 11:12:56 +10:00
Trevor Batley
2506441cfd remove start messages and tidy help 2023-06-02 09:17:03 +10:00
Trevor Batley
017fbc8857 change spec-2023 to spec-20 2023-06-02 09:11:37 +10:00
Trevor Batley
9a645a516c suppress output of git push 2023-06-01 21:23:51 +10:00
2f9f37775e remove spurious backslashes 2023-06-01 06:40:49 +02:00
59c521ee7d Remove spurious backslashes 2023-06-01 06:40:10 +02:00
f28c8f337a add rename-e-smith-pkg.sh comments + tidy 2023-06-01 06:38:29 +02:00
Trevor Batley
2c54961330 added help text for params 2023-06-01 11:05:10 +10:00
Trevor Batley
7f8546f99b comments 2023-06-01 10:50:53 +10:00
Trevor Batley
2cf3ca33bd suppress change-log output 2023-06-01 10:49:18 +10:00
Trevor Batley
bffa7d713e Add in comment re converting to regular repo 2023-06-01 10:36:25 +10:00
Trevor Batley
e189fd1b5d update summary and description in specfile 2023-06-01 10:21:54 +10:00
Trevor Batley
ab4fe843e4 use git mv rather than add/rm 2023-06-01 10:05:15 +10:00
Trevor Batley
4c5d0ded39 fix git --quiet 2023-06-01 09:56:37 +10:00
Trevor Batley
5a13da4d58 fix delete override 2023-06-01 09:41:09 +10:00
Trevor Batley
db6884d245 add force and debug options 2023-06-01 09:20:55 +10:00
Trevor Batley
8ab6930155 abort on failed delete of existing repo 2023-06-01 09:07:39 +10:00
Trevor Batley
c44114c672 minor wording in changelog 2023-05-31 21:29:18 +10:00
Trevor Batley
486fb7e6c9 remove spurious backslash in README.md 2023-05-31 18:25:19 +10:00
Trevor Batley
7081caa7ff legacy bugs link 2023-05-31 18:13:20 +10:00
Trevor Batley
79d8a3cf3b fix delete archivefilename file 2023-05-31 17:26:25 +10:00
Trevor Batley
af265e9cfe execute permissions on rename-e-smith-pkg.sh script 2023-05-31 17:21:18 +10:00
Trevor Batley
3feeb6a412 remove archivefilename file 2023-05-31 17:18:57 +10:00
Trevor Batley
19db9793df remove duplicate names 2023-05-31 17:14:29 +10:00
Trevor Batley
73b43037ad specfile updates included 2023-05-31 17:01:31 +10:00
Trevor Batley
0eeda2655a ouline of git work 2023-05-30 18:08:55 +10:00
Trevor Batley
ca0dc63f6f initial commit of rename-e-smith-pkg.sh 2023-05-30 16:34:06 +10:00
Trevor Batley
5a4f897d10 add in changelog script 2023-05-30 12:44:27 +10:00
Trevor Batley
c308b967fd revert suppress code 2023-05-25 18:10:03 +10:00
Trevor Batley
59b371fdd3 fix suppress statements 2023-05-22 11:49:42 +10:00
Trevor Batley
1498c42a41 suppress git output 2023-05-22 11:37:20 +10:00
9b82858000 fix mirror/migrate errors in doco 2023-05-16 01:03:43 +02:00
e6d2809585 fix dodo on positional parameters git-get-repo-and-build.sh 2023-05-16 01:01:14 +02:00
Trevor Batley
1f65e1cd01 fix dodgy debug line 2023-05-12 11:34:36 +10:00
Trevor Batley
1c4b06eae8 fix dodgy debug echo 2023-05-12 11:29:42 +10:00
Trevor Batley
8a0ab3a7c4 missing space 2023-05-12 10:39:23 +10:00
b6c9e66cc9 added description of review option 2023-05-12 02:31:25 +02:00
Trevor Batley
2466258187 fix optional param code 2023-05-12 10:17:18 +10:00
Trevor Batley
4a855c986b add review option 2023-05-12 08:39:20 +10:00
11f2f53a3e minor clarifications 2023-05-11 08:57:57 +02:00
Trevor Batley
6315f503a6 fix [ error 2023-05-11 16:49:37 +10:00
Trevor Batley
c7b4c6acfb fix param 2023-05-11 16:19:24 +10:00
Trevor Batley
0d8ca693a3 tidy up DEBUG 2023-05-11 15:29:55 +10:00
4ef91afbf8 formatting 2023-05-11 03:00:15 +02:00
Trevor Batley
a11a00eb25 change from mirror to migrate (copy or mirror) 2023-05-11 10:48:31 +10:00
Trevor Batley
c58aec524d put back USER for local & remote 2023-05-10 13:04:48 +10:00
Trevor Batley
43c60bac5d typo mirror-org 2023-05-10 12:38:25 +10:00
Trevor Batley
f8a1bd5bd7 fix git-mirror-org.sh 2023-05-10 12:34:09 +10:00
51594b5ee4 added details about each file 2023-05-10 02:49:40 +02:00
a7418e9bdf add comment re: user config vs system ini 2023-05-10 02:30:59 +02:00
e956432311 Add comment re: system /etc/smegit.ini file 2023-05-10 02:23:41 +02:00
Trevor Batley
93a76968ce remove unused config USER parameters 2023-05-10 10:20:42 +10:00
Trevor Batley
2edef6eb76 add system default ini and allow ~ in workdir 2023-05-10 10:17:35 +10:00
Trevor Batley
3d62c04c19 Added more debug messages 2023-05-09 18:37:35 +10:00
Trevor Batley
60d0913f48 use rm -Rf rther than complicated find -delete 2023-05-09 18:33:32 +10:00
Trevor Batley
1e64eed0c1 updated README.md with config file 2023-05-09 17:53:44 +10:00
Trevor Batley
4bd577963b added in base config (ini) file 2023-05-09 17:51:48 +10:00
33 changed files with 6678 additions and 401 deletions

204
README.md
View File

@@ -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

View 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)

View 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()

View 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()

View 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()

View 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()

View 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()

View 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
View 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
View 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>

View File

@@ -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

View 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
View 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
View 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"

View File

@@ -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
View 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
View 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
View 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
View 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

View File

@@ -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

View File

@@ -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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

17
github PR instructions Normal file
View 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
View 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
View 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
View 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
View 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
View 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"
"Submitters 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"})