Skip to content

Commit de79a82

Browse files
authored
Merge pull request #126 from tronprotocol/release-v2.2.7
Release v2.2.7 merge to main
2 parents a4d8788 + 490cc46 commit de79a82

22 files changed

Lines changed: 868 additions & 348 deletions

File tree

Lines changed: 388 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,388 @@
1+
name: Build - Artifacts
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
ref:
7+
description: 'Git ref (branch/tag/commit)'
8+
required: false
9+
default: 'main'
10+
type: string
11+
12+
permissions:
13+
id-token: write
14+
contents: read
15+
16+
env:
17+
# build.gradle $buildDir/repo
18+
CUSTOM_REPO_PATH: ${{ github.workspace }}/build/repo
19+
CUSTOM_DOWNLOAD_PATH: ${{ github.workspace }}/download/artifacts
20+
21+
jobs:
22+
build:
23+
runs-on: ubuntu-latest
24+
outputs:
25+
group: ${{ steps.set-outputs.outputs.group }}
26+
project: ${{ steps.set-outputs.outputs.project }}
27+
version: ${{ steps.set-outputs.outputs.version }}
28+
29+
steps:
30+
- name: Validate trigger source
31+
run: |
32+
set -euo pipefail
33+
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
34+
echo "✅: Manual workflow dispatch"
35+
else
36+
echo "❌: This workflow should only be manually dispatched"
37+
exit 1
38+
fi
39+
40+
- name: Checkout repository
41+
uses: actions/checkout@v5
42+
with:
43+
ref: ${{ inputs.ref }}
44+
45+
- name: Set up JDK 8
46+
uses: actions/setup-java@v5
47+
with:
48+
java-version: '8'
49+
distribution: 'temurin'
50+
51+
- name: Setup Gradle
52+
uses: gradle/actions/setup-gradle@v5
53+
with:
54+
cache-read-only: false
55+
56+
- name: Extract Project Info
57+
run: |
58+
set -euo pipefail
59+
GROUP=$(grep -E "^group\s+'[^']+'" build.gradle | sed -E "s/.*'([^']+)'.*/\1/" || true)
60+
VERSION=$(grep -E "^version\s+'[^']+'" build.gradle | sed -E "s/.*'([^']+)'.*/\1/" || true)
61+
PROJECT=$(grep -E "^rootProject\.name\s*=\s*'[^']+'" build.gradle | sed -E "s/.*'([^']+)'.*/\1/" || true)
62+
if [ -z "$PROJECT" ] && [ -f "settings.gradle" ]; then
63+
PROJECT=$(grep -E "^rootProject\.name\s*=\s*'[^']+'" settings.gradle | sed -E "s/.*'([^']+)'.*/\1/" || true)
64+
fi
65+
66+
if [ -z "$GROUP" ] || [ -z "$PROJECT" ] || [ -z "$VERSION" ]; then
67+
echo "❌: Missing group/project/version in build.gradle"
68+
exit 1
69+
fi
70+
71+
echo "group=$GROUP" >> $GITHUB_ENV
72+
echo "project=$PROJECT" >> $GITHUB_ENV
73+
echo "version=$VERSION" >> $GITHUB_ENV
74+
75+
GROUP_PATH=$(echo "$GROUP" | tr '.' '/')
76+
echo "MAVEN_GROUP_PATH=$GROUP_PATH" >> $GITHUB_ENV
77+
78+
ARTIFACT_PATH="${{ env.CUSTOM_REPO_PATH }}/$GROUP_PATH/$PROJECT/$VERSION"
79+
echo "ARTIFACT_PATH=$ARTIFACT_PATH" >> $GITHUB_ENV
80+
81+
echo "✅ Project: $PROJECT, Version: $VERSION, Group: $GROUP"
82+
83+
- name: Publish to CI Maven repository
84+
run: ./gradlew clean -xtest -xcheck --refresh-dependencies publishAllPublicationsToCiLocalRepository
85+
86+
- name: Verify artifacts and checksums
87+
run: |
88+
set -euo pipefail
89+
if [ ! -d "${{ env.ARTIFACT_PATH }}" ]; then
90+
echo "❌: Artifacts not found at ${{ env.ARTIFACT_PATH }}"
91+
exit 1
92+
fi
93+
94+
REQUIRED_FILES=(
95+
"${{ env.project }}-${{ env.version }}.jar"
96+
"${{ env.project }}-${{ env.version }}.jar.md5"
97+
"${{ env.project }}-${{ env.version }}.jar.sha1"
98+
"${{ env.project }}-${{ env.version }}.jar.sha256"
99+
"${{ env.project }}-${{ env.version }}.jar.sha512"
100+
"${{ env.project }}-${{ env.version }}.module"
101+
"${{ env.project }}-${{ env.version }}.module.md5"
102+
"${{ env.project }}-${{ env.version }}.module.sha1"
103+
"${{ env.project }}-${{ env.version }}.module.sha256"
104+
"${{ env.project }}-${{ env.version }}.module.sha512"
105+
"${{ env.project }}-${{ env.version }}.pom"
106+
"${{ env.project }}-${{ env.version }}.pom.md5"
107+
"${{ env.project }}-${{ env.version }}.pom.sha1"
108+
"${{ env.project }}-${{ env.version }}.pom.sha256"
109+
"${{ env.project }}-${{ env.version }}.pom.sha512"
110+
"${{ env.project }}-${{ env.version }}-javadoc.jar"
111+
"${{ env.project }}-${{ env.version }}-javadoc.jar.md5"
112+
"${{ env.project }}-${{ env.version }}-javadoc.jar.sha1"
113+
"${{ env.project }}-${{ env.version }}-javadoc.jar.sha256"
114+
"${{ env.project }}-${{ env.version }}-javadoc.jar.sha512"
115+
"${{ env.project }}-${{ env.version }}-sources.jar"
116+
"${{ env.project }}-${{ env.version }}-sources.jar.md5"
117+
"${{ env.project }}-${{ env.version }}-sources.jar.sha1"
118+
"${{ env.project }}-${{ env.version }}-sources.jar.sha256"
119+
"${{ env.project }}-${{ env.version }}-sources.jar.sha512"
120+
)
121+
122+
MISSING_FILES=()
123+
for file in "${REQUIRED_FILES[@]}"; do
124+
if [ ! -f "${{ env.ARTIFACT_PATH }}/$file" ]; then
125+
MISSING_FILES+=("$file")
126+
fi
127+
done
128+
129+
if [ ${#MISSING_FILES[@]} -gt 0 ]; then
130+
echo "❌ Missing required files:"
131+
for f in "${MISSING_FILES[@]}"; do echo " - $f"; done
132+
exit 1
133+
fi
134+
135+
echo "✅ All required files verified (${#REQUIRED_FILES[@]} files)"
136+
137+
- name: Remove Maven metadata files
138+
run: |
139+
set -euo pipefail
140+
DELETED_COUNT=$(find ${{ env.CUSTOM_REPO_PATH }} -name "maven-metadata*" -type f -delete -print | wc -l)
141+
echo "✅ Removed $DELETED_COUNT Maven metadata files"
142+
143+
- name: Upload publish files
144+
uses: actions/upload-artifact@v4
145+
with:
146+
name: ${{ env.project }}-${{ env.version }}-artifacts
147+
path: ${{ env.CUSTOM_REPO_PATH }}/
148+
if-no-files-found: error
149+
retention-days: 30
150+
151+
- name: Set Outputs
152+
id: set-outputs
153+
run: |
154+
set -euo pipefail
155+
echo "group=${{ env.MAVEN_GROUP_PATH }}" >> $GITHUB_OUTPUT
156+
echo "project=${{ env.project }}" >> $GITHUB_OUTPUT
157+
echo "version=${{ env.version }}" >> $GITHUB_OUTPUT
158+
159+
- name: Generate summary
160+
run: |
161+
set -euo pipefail
162+
COMMIT_ID=$(git rev-parse HEAD)
163+
COMMIT_MSG=$(git log -1 --pretty=%B)
164+
echo "## Build Summary" >> $GITHUB_STEP_SUMMARY
165+
echo "" >> $GITHUB_STEP_SUMMARY
166+
echo "- **Project:** ${{ env.project }}" >> $GITHUB_STEP_SUMMARY
167+
echo "- **Version:** ${{ env.version }}" >> $GITHUB_STEP_SUMMARY
168+
echo "- **Group:** ${{ env.MAVEN_GROUP_PATH }}" >> $GITHUB_STEP_SUMMARY
169+
echo "- **Git Ref:** ${{ inputs.ref }}" >> $GITHUB_STEP_SUMMARY
170+
echo "- **Commit ID:** $COMMIT_ID" >> $GITHUB_STEP_SUMMARY
171+
echo "- **Commit Message:** $COMMIT_MSG" >> $GITHUB_STEP_SUMMARY
172+
echo "" >> $GITHUB_STEP_SUMMARY
173+
174+
echo "### Local Repository Files" >> $GITHUB_STEP_SUMMARY
175+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
176+
ls -lh "${{ env.ARTIFACT_PATH }}" >> $GITHUB_STEP_SUMMARY
177+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
178+
echo "- **Artifact Check:** ✓ All required files present" >> $GITHUB_STEP_SUMMARY
179+
echo "" >> $GITHUB_STEP_SUMMARY
180+
181+
sign-and-upload:
182+
runs-on: self-hosted
183+
needs: build
184+
steps:
185+
- name: Validate secrets
186+
run: |
187+
set -euo pipefail
188+
if [ -z "${{ secrets.GPG_FINGERPRINT }}" ]; then
189+
echo "❌: GPG_FINGERPRINT secret not configured"
190+
exit 1
191+
fi
192+
if [ -z "${{ secrets.S3_BUCKET_PRE_STAGE }}" ]; then
193+
echo "❌: S3_BUCKET_PRE_STAGE secret not configured"
194+
exit 1
195+
fi
196+
if [ -z "${{ secrets.AWS_ROLE_ARN_PRE_STAGE_UPLOAD }}" ]; then
197+
echo "❌: AWS_ROLE_ARN_PRE_STAGE_UPLOAD secret not configured"
198+
exit 1
199+
fi
200+
if [ -z "${{ secrets.AWS_REGION }}" ]; then
201+
echo "❌: AWS_REGION secret not configured"
202+
exit 1
203+
fi
204+
echo "✅ All required secrets configured"
205+
206+
- name: Download artifacts
207+
uses: actions/download-artifact@v4
208+
with:
209+
name: ${{ needs.build.outputs.project }}-${{ needs.build.outputs.version }}-artifacts
210+
path: ${{ env.CUSTOM_DOWNLOAD_PATH }}
211+
212+
- name: Verify downloaded artifacts
213+
run: |
214+
set -euo pipefail
215+
FULL_PATH="${{ env.CUSTOM_DOWNLOAD_PATH }}/${{ needs.build.outputs.group }}/${{ needs.build.outputs.project }}/${{ needs.build.outputs.version }}"
216+
if [ ! -d "$FULL_PATH" ]; then
217+
echo "❌: Downloaded artifacts not found at expected path"
218+
exit 1
219+
fi
220+
FILE_COUNT=$(find "$FULL_PATH" -type f | wc -l)
221+
echo "✅: Downloaded $FILE_COUNT files to $FULL_PATH"
222+
echo "FULL_PATH=$FULL_PATH" >> $GITHUB_ENV
223+
224+
- name: Wait for hardware key (YubiKey/HSM)
225+
run: |
226+
set -euo pipefail
227+
echo "⏳ Waiting for GPG hardware key..."
228+
MAX_RETRIES=60
229+
RETRY_INTERVAL=2
230+
for i in $(seq 1 $MAX_RETRIES); do
231+
if gpg --card-status > /dev/null 2>&1; then
232+
echo "✅: GPG hardware key detected and ready (after $((i*RETRY_INTERVAL))s)"
233+
break
234+
fi
235+
echo "[$i/$MAX_RETRIES] Hardware key not detected, retrying in ${RETRY_INTERVAL}s..."
236+
sleep $RETRY_INTERVAL
237+
done
238+
239+
if ! gpg --card-status > /dev/null 2>&1; then
240+
echo "❌ Timeout waiting for hardware key after $((MAX_RETRIES*RETRY_INTERVAL)) seconds"
241+
exit 1
242+
fi
243+
244+
- name: Sign artifacts
245+
run: |
246+
set -euo pipefail
247+
cd "${{ env.FULL_PATH }}"
248+
249+
PREFIX="${{ needs.build.outputs.project }}-${{ needs.build.outputs.version }}"
250+
FILES=(
251+
"${PREFIX}.jar"
252+
"${PREFIX}.module"
253+
"${PREFIX}-sources.jar"
254+
"${PREFIX}-javadoc.jar"
255+
"${PREFIX}.pom"
256+
)
257+
258+
compute_md5() {
259+
if command -v md5sum >/dev/null 2>&1; then
260+
md5sum "$1" | awk '{print $1}'
261+
else
262+
md5 "$1" | awk '{print $4}'
263+
fi
264+
}
265+
266+
SIGNED_COUNT=0
267+
for file in "${FILES[@]}"; do
268+
if [ ! -f "$file" ]; then
269+
echo "❌ Missing file to sign: $file"
270+
exit 1
271+
fi
272+
echo "Signing $file..."
273+
gpg --quiet --batch --yes --local-user ${{ secrets.GPG_FINGERPRINT }} --armor --detach-sign "$file"
274+
compute_md5 ${file}.asc > ${file}.asc.md5
275+
shasum -a 1 ${file}.asc | awk '{print $1}' > ${file}.asc.sha1
276+
shasum -a 256 ${file}.asc | awk '{print $1}' > ${file}.asc.sha256
277+
shasum -a 512 ${file}.asc | awk '{print $1}' > ${file}.asc.sha512
278+
SIGNED_COUNT=$((SIGNED_COUNT + 1))
279+
done
280+
echo "✓ Successfully signed $SIGNED_COUNT files"
281+
282+
- name: Verify signatures
283+
run: |
284+
set -euo pipefail
285+
cd "${{ env.FULL_PATH }}"
286+
VERIFIED_COUNT=0
287+
FAILED_SIGS=()
288+
for sig in *.asc; do
289+
if [ -f "$sig" ]; then
290+
echo "Verifying $sig..."
291+
if ! gpg --verify "$sig" "${sig%.asc}" > /dev/null 2>&1; then
292+
FAILED_SIGS+=("$sig")
293+
else
294+
VERIFIED_COUNT=$((VERIFIED_COUNT + 1))
295+
fi
296+
fi
297+
done
298+
299+
if [ ${#FAILED_SIGS[@]} -gt 0 ]; then
300+
echo "❌ Signature verification failed for: ${FAILED_SIGS[*]}"
301+
exit 1
302+
fi
303+
echo "✅ All $VERIFIED_COUNT signatures verified"
304+
305+
- name: Zip signed artifacts
306+
run: |
307+
set -euo pipefail
308+
cd ${{ env.CUSTOM_DOWNLOAD_PATH }}
309+
BUNDLE_NAME="${{ needs.build.outputs.project }}-${{ needs.build.outputs.version }}-bundle.zip"
310+
zip -r "$BUNDLE_NAME" ${{ needs.build.outputs.group }} >/dev/null
311+
if [ ! -f "$BUNDLE_NAME" ]; then
312+
echo "❌ Error: Bundle file not created"
313+
exit 1
314+
fi
315+
316+
BUNDLE_SIZE=$(du -h "$BUNDLE_NAME" | cut -f1)
317+
echo "✓ Bundle created: $BUNDLE_NAME (${BUNDLE_SIZE})"
318+
echo "BUNDLE_NAME=$BUNDLE_NAME" >> $GITHUB_ENV
319+
echo "BUNDLE_SIZE=$BUNDLE_SIZE" >> $GITHUB_ENV
320+
321+
- name: Verify bundle contents
322+
run: |
323+
set -euo pipefail
324+
cd ${{ env.CUSTOM_DOWNLOAD_PATH }}
325+
echo "Bundle contents:"
326+
unzip -l "${{ env.BUNDLE_NAME }}" | head -50
327+
328+
ASC_COUNT=$(unzip -l "${{ env.BUNDLE_NAME }}" | grep -c "\.asc$" || true)
329+
if [ "$ASC_COUNT" -lt 5 ]; then
330+
echo "❌ Bundle missing signature files (found $ASC_COUNT)"
331+
exit 1
332+
fi
333+
echo "✅ Bundle verified: contains $ASC_COUNT signature files"
334+
335+
- name: Upload signed bundle
336+
uses: actions/upload-artifact@v4
337+
with:
338+
name: ${{ needs.build.outputs.project }}-${{ needs.build.outputs.version }}-bundle
339+
path: ${{ env.CUSTOM_DOWNLOAD_PATH }}/${{ env.BUNDLE_NAME }}
340+
retention-days: 30
341+
342+
- name: Configure AWS Credentials (OIDC)
343+
uses: aws-actions/configure-aws-credentials@v4
344+
with:
345+
role-to-assume: ${{ secrets.AWS_ROLE_ARN_PRE_STAGE_UPLOAD }}
346+
aws-region: ${{ secrets.AWS_REGION }}
347+
348+
- name: Upload artifacts to S3
349+
run: |
350+
set -euo pipefail
351+
cd ${{ env.CUSTOM_DOWNLOAD_PATH }}
352+
353+
DEST="s3://${{ secrets.S3_BUCKET_PRE_STAGE }}"
354+
if [ -n "${{ secrets.S3_PREFIX }}" ]; then
355+
DEST="$DEST/${{ secrets.S3_PREFIX }}"
356+
fi
357+
DEST="$DEST/${{ needs.build.outputs.version }}"
358+
echo "Uploading ${{ env.BUNDLE_NAME }}"
359+
aws s3 cp "${{ env.BUNDLE_NAME }}" "$DEST/" --only-show-errors
360+
echo "✅ Successfully uploaded to S3"
361+
362+
- name: Generate upload summary
363+
if: success()
364+
run: |
365+
set -euo pipefail
366+
echo "## ✅ Artifact Signing & Upload Summary" >> $GITHUB_STEP_SUMMARY
367+
echo "" >> $GITHUB_STEP_SUMMARY
368+
echo "### Project Information" >> $GITHUB_STEP_SUMMARY
369+
echo "- **Project:** ${{ needs.build.outputs.project }}" >> $GITHUB_STEP_SUMMARY
370+
echo "- **Version:** ${{ needs.build.outputs.version }}" >> $GITHUB_STEP_SUMMARY
371+
echo "- **Group Path:** ${{ needs.build.outputs.group }}" >> $GITHUB_STEP_SUMMARY
372+
echo "" >> $GITHUB_STEP_SUMMARY
373+
echo "### Bundle Details" >> $GITHUB_STEP_SUMMARY
374+
echo "- **Bundle Name:** \`${{ env.BUNDLE_NAME }}\`" >> $GITHUB_STEP_SUMMARY
375+
echo "- **Bundle Size:** ${{ env.BUNDLE_SIZE }}" >> $GITHUB_STEP_SUMMARY
376+
echo "" >> $GITHUB_STEP_SUMMARY
377+
echo "### Signed Files" >> $GITHUB_STEP_SUMMARY
378+
find "${{ env.FULL_PATH }}" -type f -name "*.asc" -exec basename {} \; | sed 's/^/- /' >> $GITHUB_STEP_SUMMARY
379+
echo "" >> $GITHUB_STEP_SUMMARY
380+
echo "**Upload Time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
381+
echo "" >> $GITHUB_STEP_SUMMARY
382+
383+
- name: Cleanup downloaded artifacts
384+
if: always()
385+
run: |
386+
set -euo pipefail
387+
rm -rf "${{ env.CUSTOM_DOWNLOAD_PATH }}" || true
388+
echo "✅ Cleaned up downloaded artifacts"

0 commit comments

Comments
 (0)