@@ -13,6 +13,155 @@ readonly capture_apollo_archive="$4"
1313readonly capture_plugin_archive=" $5 "
1414readonly capture_plugin_marker_archive=" $6 "
1515
16+ # ############################################
17+ # Helpers for Maven Central bundle creation #
18+ # ############################################
19+
20+ # Import a GPG private key if provided via env vars.
21+ # Supports either raw ASCII-armored key in GPG_PRIVATE_KEY or base64-encoded in GPG_PRIVATE_KEY_BASE64.
22+ function import_gpg_key_if_available() {
23+ if [[ -z " ${GPG_PRIVATE_KEY:- ${GPG_PRIVATE_KEY_BASE64:- } } " ]]; then
24+ echo " GPG signing key not provided; cannot proceed with Maven Central bundle creation." >&2
25+ exit 1
26+ fi
27+
28+ # Ensure gpg is available
29+ if ! command -v gpg > /dev/null 2>&1 ; then
30+ echo " gpg is required to sign artifacts; please install it in the CI runner." >&2
31+ exit 1
32+ fi
33+
34+ # Create a temp GNUPGHOME to avoid polluting the runner account
35+ GNUPGHOME=" $( mktemp -d) "
36+ export GNUPGHOME
37+ chmod 700 " $GNUPGHOME "
38+
39+ # Decode if necessary and import (ensure no command echo)
40+ local _xtrace_was_on=0
41+ case $- in
42+ * x* ) _xtrace_was_on=1; set +x ;;
43+ esac
44+
45+ # Prepare temp files
46+ local -r key_raw_file=" $( mktemp) "
47+ local -r key_sanitized_file=" $( mktemp) "
48+
49+ if [[ -n " ${GPG_PRIVATE_KEY_BASE64:- } " ]]; then
50+ printf ' %s' " $GPG_PRIVATE_KEY_BASE64 " | base64 -d > " $key_raw_file "
51+ else
52+ printf ' %s' " $GPG_PRIVATE_KEY " > " $key_raw_file "
53+ fi
54+
55+ # Normalize line endings and extract only the private key block(s)
56+ tr -d ' \r' < " $key_raw_file " | \
57+ sed -n ' /-----BEGIN PGP .*PRIVATE KEY BLOCK-----/,/-----END PGP .*PRIVATE KEY BLOCK-----/p' > " $key_sanitized_file "
58+
59+ # If sanitize produced nothing, fall back to raw file
60+ local import_file=" $key_sanitized_file "
61+ if [[ ! -s " $import_file " ]]; then
62+ import_file=" $key_raw_file "
63+ fi
64+
65+ # Import, but don't fail the whole script if gpg returns non-zero due to warnings
66+ set +e
67+ gpg --batch --yes --import " $import_file "
68+ local gpg_rc=$?
69+ set -e
70+ # If gpg returned a non-zero code, log and continue; we'll verify presence of a secret key below.
71+ if (( gpg_rc != 0 )) ; then
72+ echo " gpg import exited with code $gpg_rc ; continuing and verifying secret key presence." >&2
73+ fi
74+
75+ # Verify a secret key is available after import
76+ if ! gpg --batch --list-secret-keys > /dev/null 2>&1 ; then
77+ echo " Failed to import GPG private key for signing." >&2
78+ rm -f " $key_raw_file " " $key_sanitized_file "
79+ exit 1
80+ fi
81+
82+ # Cleanup
83+ rm -f " $key_raw_file " " $key_sanitized_file "
84+ if [[ $_xtrace_was_on -eq 1 ]]; then set -x; fi
85+
86+ # Do not print any key details to logs to avoid leaking identifiers
87+ }
88+
89+ function sign_file() {
90+ local -r file=" $1 "
91+ # --armor --detach-sign to create .asc
92+ local _xtrace_was_on=0
93+ case $- in * x* ) _xtrace_was_on=1; set +x ;; esac
94+ if [[ -n " ${GPG_PASSPHRASE:- } " ]]; then
95+ if [[ -n " ${GPG_KEY_ID:- } " ]]; then
96+ printf ' %s' " $GPG_PASSPHRASE " | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 -u " $GPG_KEY_ID " --armor --detach-sign " $file "
97+ else
98+ printf ' %s' " $GPG_PASSPHRASE " | gpg --batch --yes --pinentry-mode loopback --passphrase-fd 0 --armor --detach-sign " $file "
99+ fi
100+ else
101+ if [[ -n " ${GPG_KEY_ID:- } " ]]; then
102+ gpg --batch --yes --pinentry-mode loopback -u " $GPG_KEY_ID " --armor --detach-sign " $file "
103+ else
104+ gpg --batch --yes --pinentry-mode loopback --armor --detach-sign " $file "
105+ fi
106+ fi
107+ if [[ $_xtrace_was_on -eq 1 ]]; then set -x; fi
108+ }
109+
110+ function generate_all_checksums() {
111+ local -r file=" $1 "
112+ " $sdk_repo /ci/checksum.sh" md5 " $file "
113+ " $sdk_repo /ci/checksum.sh" sha1 " $file "
114+ " $sdk_repo /ci/checksum.sh" sha256 " $file "
115+ " $sdk_repo /ci/checksum.sh" sha512 " $file "
116+ }
117+
118+ # Create Maven Central-ready structure under dist/maven-central for a single artifact
119+ # Args:
120+ # $1 - group path (e.g., io/bitdrift)
121+ # $2 - artifact id (e.g., capture)
122+ # $3 - version
123+ # $4.. - files to include (must be located in current CWD)
124+ function package_maven_central_bundle() {
125+ local -r group_path=" $1 "
126+ local -r artifact_id=" $2 "
127+ local -r ver=" $3 "
128+ shift 3
129+ local -a files=(" $@ " )
130+
131+ local -r out_root=" $sdk_repo /dist/maven-central/$group_path /$artifact_id /$ver "
132+ mkdir -p " $out_root "
133+
134+ # Copy, sign, and checksum primary files
135+ for f in " ${files[@]} " ; do
136+ if [[ ! -f " $f " ]]; then
137+ echo " Warning: expected file '$f ' not found; skipping." >&2
138+ continue
139+ fi
140+ # Exclude LICENSE/NOTICE from Maven Central bundles (even if accidentally provided)
141+ case " $( basename " $f " | tr ' [:upper:]' ' [:lower:]' ) " in
142+ license|license.* |notice|notice.* )
143+ echo " Excluding $( basename " $f " ) from Maven Central bundle"
144+ continue
145+ ;;
146+ esac
147+ cp -f " $f " " $out_root /"
148+ pushd " $out_root " > /dev/null
149+ sign_file " $( basename " $f " ) "
150+ generate_all_checksums " $( basename " $f " ) "
151+ popd > /dev/null
152+ done
153+
154+ # Zip the group root to ease upload via Sonatype UI/API
155+ local -r zip_out_dir=" $sdk_repo /dist/maven-central"
156+ mkdir -p " $zip_out_dir "
157+ local -r zip_name=" ${artifact_id} -${ver} .maven-central.zip"
158+ pushd " $zip_out_dir " > /dev/null
159+ # Create a zip that contains the repo path starting from the group root
160+ zip -r " $zip_name " " $group_path /$artifact_id /$ver " > /dev/null
161+ popd > /dev/null
162+ echo " Created Maven Central bundle: $zip_out_dir /$zip_name "
163+ }
164+
16165function upload_file() {
17166 local -r location=" $1 "
18167 local -r file=" $2 "
@@ -23,8 +172,10 @@ function upload_file() {
23172 " $sdk_repo /ci/checksum.sh" sha512 " $file "
24173
25174 for f in " $file " " $file .md5" " $file .sha1" " $file .sha256" " $file .sha512" ; do
26- echo " Uploading $file ..."
27- aws s3 cp " $f " " $location /$f " --region us-east-1
175+ local base
176+ base=" $( basename " $f " ) "
177+ echo " Uploading $base to $location /"
178+ aws s3 cp " $f " " $location /$base " --region us-east-1
28179 done
29180}
30181
@@ -40,12 +191,12 @@ function generate_maven_file() {
40191 awk ' {print $2}' |
41192 sed ' s/^\///;s/\/$//' )
42193
43- python3 " $sdk_repo /ci/generate_maven_metadata.py" --releases " ${releases// $' \n ' / ,} " --library " library_name"
194+ python3 " $sdk_repo /ci/generate_maven_metadata.py" --releases " ${releases// $' \n ' / ,} " --library " $ library_name"
44195
45196 echo " +++ Generated maven-metadata.xml:"
46197 cat maven-metadata.xml
47198
48- upload_file " $remote_location_prefix " " maven-metadata.xml"
199+ upload_file " $location " " maven-metadata.xml"
49200}
50201
51202function release_capture_sdk() {
@@ -78,6 +229,10 @@ function release_capture_sdk() {
78229 done
79230
80231 generate_maven_file " $remote_location_prefix " " capture"
232+
233+ # Prepare Maven Central bundle (group: io/bitdrift, artifact: capture)
234+ package_maven_central_bundle " io/bitdrift" " capture" " $version " \
235+ " $name .pom" " $name -javadoc.jar" " $name -sources.jar" " $name .aar"
81236 popd
82237}
83238
@@ -100,6 +255,32 @@ function release_gradle_library() {
100255 aws s3 cp . " $remote_location_prefix /$version /" --recursive --region us-east-1
101256
102257 generate_maven_file " $remote_location_prefix " " $library_name "
258+
259+ # Prepare Maven Central bundle (group: io/bitdrift, artifact: $library_name)
260+ # Try to derive base from .pom name
261+ shopt -s nullglob
262+ local poms=( * .pom )
263+ if (( ${# poms[@]} > 0 )) ; then
264+ local base=" ${poms[0]% .pom} "
265+ # Select common files if present
266+ local -a bundle_files=( " $base .pom" )
267+ [[ -f " $base .jar" ]] && bundle_files+=( " $base .jar" )
268+ [[ -f " $base .aar" ]] && bundle_files+=( " $base .aar" )
269+ [[ -f " $base -sources.jar" ]] && bundle_files+=( " $base -sources.jar" )
270+ [[ -f " $base -javadoc.jar" ]] && bundle_files+=( " $base -javadoc.jar" )
271+ # Explicitly exclude LICENSE/NOTICE from bundle files if present nearby
272+ for i in " ${! bundle_files[@]} " ; do
273+ case " $( basename " ${bundle_files[$i]} " | tr ' [:upper:]' ' [:lower:]' ) " in
274+ license|license.* |notice|notice.* )
275+ unset ' bundle_files[$i]'
276+ ;;
277+ esac
278+ done
279+ package_maven_central_bundle " io/bitdrift" " $library_name " " $version " " ${bundle_files[@]} "
280+ else
281+ echo " Warning: No .pom found for $library_name ; skipping Maven Central bundle."
282+ fi
283+ shopt -u nullglob
103284 popd
104285}
105286
@@ -121,9 +302,13 @@ function release_gradle_plugin() {
121302 aws s3 cp . " $remote_location_prefix /$version /" --recursive --region us-east-1
122303
123304 generate_maven_file " $remote_location_prefix " " $plugin_marker "
305+
124306 popd
125307}
126308
309+ # If requested, set up GPG for signing
310+ import_gpg_key_if_available
311+
127312release_capture_sdk
128313release_gradle_library " capture-timber" " $capture_timber_archive "
129314release_gradle_library " capture-apollo" " $capture_apollo_archive "
0 commit comments