From e626573dfdc67c0d39381e39ac5165b14ea50f73 Mon Sep 17 00:00:00 2001 From: 0xbigapple Date: Tue, 9 Dec 2025 14:58:32 +0800 Subject: [PATCH] feat(ci): Support ci, generate and publish artifacts, gpg sign --- .../gradle-generate-publish-artifacts.yml | 198 ++++++++++++++++++ .github/workflows/sign-publish-artifacts.yml | 193 +++++++++++++++++ build.gradle | 11 +- 3 files changed, 396 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/gradle-generate-publish-artifacts.yml create mode 100644 .github/workflows/sign-publish-artifacts.yml diff --git a/.github/workflows/gradle-generate-publish-artifacts.yml b/.github/workflows/gradle-generate-publish-artifacts.yml new file mode 100644 index 00000000..eb2baba1 --- /dev/null +++ b/.github/workflows/gradle-generate-publish-artifacts.yml @@ -0,0 +1,198 @@ +name: Build - Artifacts + +on: + workflow_dispatch: + inputs: + project_version: + description: "Project version (e.g. 1.0.0)" + required: true + default: "" + project_group: + description: "Project group (e.g. io.github.tronprotocol)" + required: true + default: "io.github.tronprotocol" + +permissions: + id-token: write # Only allow OIDC token access + contents: read # Limit repository access + +jobs: + build: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up JDK 8 + run: | + export JDK_TAR="jdk-8u202-linux-x64.tar.gz" + export JDK_DIR="jdk1.8.0_202" + export JDK_MD5="0029351f7a946f6c05b582100c7d45b7" + set -o errexit -o nounset + sudo apt-get update && sudo apt-get install -y wget + sudo wget -P /usr/local https://github.com/frekele/oracle-java/releases/download/8u202-b08/$JDK_TAR + echo "$JDK_MD5 /usr/local/$JDK_TAR" | md5sum -c + sudo tar -zxf /usr/local/$JDK_TAR -C /usr/local + sudo rm /usr/local/$JDK_TAR + echo "JAVA_HOME=/usr/local/$JDK_DIR" >> $GITHUB_ENV + echo "CLASSPATH=/usr/local/$JDK_DIR/lib/dt.jar:/usr/local/$JDK_DIR/lib/tools.jar" >> $GITHUB_ENV + echo "/usr/local/$JDK_DIR/bin" >> $GITHUB_PATH + + # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. + # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: ${{ github.event_name == 'pull_request' }} + # This prevents pull requests from polluting the cache with potentially unstable changes. + + # --- Regular Gradle build (with dependency verification) --- + - name: Build project + run: ./gradlew clean build -x test -PVERSION=${{ inputs.project_version }} -PGROUP=${{ inputs.project_group }} + + # --- Create init.gradle for publishing --- + - name: Create Gradle init script for publishing + run: | + cat > init-publish.gradle <<'EOF' + allprojects { + // Apply Java and Maven Publish plugins + apply plugin: 'java' + apply plugin: 'maven-publish' + + publishing { + publications { + mavenJava(MavenPublication) { + from components.java + + groupId = "${{ inputs.project_group }}" + artifactId = 'trident' + version = "${{ inputs.project_version }}" + + pom { + name = 'trident' + description = 'Java implementation of trident' + url = 'https://github.com/tronprotocol/trident' + + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + + developers { + developer { + name = 'jiangyuanshu' + email = '317787106@qq.com' + } + developer { + name = 'apple' + email = 'apple0xlee@gmail.com' + } + } + + scm { + connection = 'scm:git:git://github.com/tronprotocol/trident.git' + developerConnection = 'scm:git:ssh://github.com/tronprotocol/trident.git' + url = 'https://github.com/tronprotocol/trident' + } + + // collect all dependencies of subprojects + withXml { + def dependenciesNode = asNode().appendNode('dependencies') + def seenDependencies = [] as Set + subprojects.each { subproject -> + { + subproject.properties.configurations.implementation.allDependencies.each { dep -> + {//println dep + if (!(dep instanceof ProjectDependency) && dep.group != null && dep.name != null && dep.version != null && dep.group != artifactId) { + def dependencyIdentifier = "${dep.group}:${dep.name}:${dep.version}" + //drop duplicate + if (!seenDependencies.contains(dependencyIdentifier)) { + seenDependencies << dependencyIdentifier + def dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('groupId', dep.group) + dependencyNode.appendNode('artifactId', dep.name) + dependencyNode.appendNode('version', dep.version) + //dependencyNode.appendNode('scope', 'runtime') + + // for exclusions + if (dep.excludeRules.size() > 0) { + def exclusions = dependencyNode.appendNode('exclusions') + dep.excludeRules.each { ExcludeRule ex -> + def exclusion = exclusions.appendNode('exclusion') + exclusion.appendNode('groupId', ex.group) + exclusion.appendNode('artifactId', ex.module) + } + } + } + }// end if + } + } + } + } + } + //end withXml + } + } + } + + repositories { + mavenLocal() + } + } + } + EOF + + # --- Generate POM using init script --- + - name: Generate POM file + run: ./gradlew generatePomFileForMavenJavaPublication -I init-publish.gradle + + # --- Upload generated POM as artifact --- + - name: Upload POM file + uses: actions/upload-artifact@v4 + with: + name: generated-pom + path: build/publications/mavenJava/pom-default.xml + + - name: Upload JAR files + uses: actions/upload-artifact@v4 + with: + name: trident-${{ inputs.project_version }} + path: build/libs/*.jar + + # --- AWS S3 Upload Section --- + - name: Configure AWS Credentials (OIDC) + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN_DEV_UPLOAD }} # 👈 replace with your IAM role + aws-region: ${{ secrets.AWS_REGION }} + + - name: Upload artifacts to S3 + run: | + DEST="s3://${{ secrets.S3_BUCKET_DEV }}" + if [ -n "${{ secrets.S3_PREFIX }}" ]; then + DEST="$DEST/${{ secrets.S3_PREFIX }}" + fi + DEST="$DEST/${{ inputs.project_version }}" + aws s3 cp build/publications/mavenJava/pom-default.xml "$DEST/trident-${{ inputs.project_version }}.pom" + aws s3 cp build/libs/ "$DEST/" --recursive --exclude "*" --include "*.jar" + + echo "## MD5 Summary of Uploaded Files" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Filename | MD5 Hash |" >> $GITHUB_STEP_SUMMARY + echo "|----------|----------|" >> $GITHUB_STEP_SUMMARY + for file in build/libs/*.jar; do + if [ -f "$file" ]; then + FILENAME=$(basename "$file") + LOCAL_MD5=$(md5sum $file | awk '{print $1}') + echo "| $FILENAME | $LOCAL_MD5 |" >> $GITHUB_STEP_SUMMARY + echo "$FILENAME: $LOCAL_MD5" + fi + done + + LOCAL_MD5=$(md5sum build/publications/mavenJava/pom-default.xml | awk '{print $1}') + echo "| trident-${{ inputs.project_version }}.pom | $LOCAL_MD5 |" >> $GITHUB_STEP_SUMMARY + echo "trident-${{ inputs.project_version }}.pom: $LOCAL_MD5" + diff --git a/.github/workflows/sign-publish-artifacts.yml b/.github/workflows/sign-publish-artifacts.yml new file mode 100644 index 00000000..58c92dfa --- /dev/null +++ b/.github/workflows/sign-publish-artifacts.yml @@ -0,0 +1,193 @@ +name: Sign - Artifacts + +on: + workflow_dispatch: + inputs: + project_version: + description: "Project version (e.g. 1.0.0)" + required: true + default: "" + project_group: + description: "Project group (e.g. io.github.tronprotocol)" + required: true + default: "io.github.tronprotocol" + +jobs: + + + download-from-s3-and-sign: + name: Download from S3 + runs-on: self-hosted + + permissions: + contents: read + id-token: write # Needed for AWS credential provider + + steps: + - name: Set S3 path + run: | + echo "S3_PATH=${{ secrets.S3_BUCKET_DEV }}/${{ secrets.S3_PREFIX }}/${{ inputs.project_version }}" >> $GITHUB_ENV + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN_DEV_DOWNLOAD }} # 👈 replace with your IAM role + aws-region: ${{ secrets.AWS_REGION }} + + - name: Compute DOWNLOAD_DIR + run: | + GROUP_PATH=$(echo "${{ inputs.project_group }}" | tr '.' '/') + echo "DOWNLOAD_DIR=$GROUP_PATH/trident/${{ inputs.project_version }}" >> $GITHUB_ENV + + - name: Create download directory + run: | + if [ -d "${{ env.DOWNLOAD_DIR }}" ]; then + rm -rf "${{ env.DOWNLOAD_DIR }}" + fi + mkdir -p ${{ env.DOWNLOAD_DIR }} + + - name: Download files from S3 + run: | + echo "Downloading files from ${{ env.S3_PATH }}" + aws s3 cp s3://${{ env.S3_PATH }}/ ${{ env.DOWNLOAD_DIR }}/ --recursive --exclude "*" --include "trident-${{ inputs.project_version }}*" + + # Verify download was successful + if [ -z "$(ls -A ${{ env.DOWNLOAD_DIR }})" ]; then + echo "Error: Failed to download files from S3" + exit 1 + else + echo "Download from S3 completed successfully" + ls -l "${{ env.DOWNLOAD_DIR }}" | awk '{ $3=""; $4=""; print }' + fi + + - name: Create download summary + run: | + echo "## S3 Download Summary" >> $GITHUB_STEP_SUMMARY + echo "Downloaded files from \`${{ env.S3_PATH }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Downloaded Files:" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + ls -l "${{ env.DOWNLOAD_DIR }}" | awk '{ $3=""; $4=""; print }' >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + + echo "### MD5 Summary of Downloaded Files" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Filename | MD5 Hash |" >> $GITHUB_STEP_SUMMARY + echo "|----------|----------|" >> $GITHUB_STEP_SUMMARY + for file in ${{ env.DOWNLOAD_DIR }}/*; do + if [ -f "$file" ]; then + FILENAME=$(basename "$file") + LOCAL_MD5=$(md5sum $file | awk '{print $1}') + echo "| $FILENAME | $LOCAL_MD5 |" >> $GITHUB_STEP_SUMMARY + echo "$FILENAME: $LOCAL_MD5" + fi + done + + - name: List files to sign + run: | + echo "Files to sign:" + ls -l ${{ env.DOWNLOAD_DIR }} | awk '{ $3=""; $4=""; print }' + + - name: Sign artifacts + run: | + # Sign each JAR file + PREFIX="${{ env.DOWNLOAD_DIR }}/trident-${{ inputs.project_version }}" + + files=( + "${PREFIX}.jar" + "${PREFIX}-sources.jar" + "${PREFIX}-javadoc.jar" + "${PREFIX}.pom" + ) + for file in "${files[@]}"; do + if [ -f "$file" ]; then + echo "Signing $file" + # Generate GPG signature + gpg --local-user ${{ secrets.GPG_FINGERPRINT }} --armor --detach-sign ${file} + # Generate checksums (macOS-specific commands) + md5 ${file} | awk '{print $NF}' > ${file}.md5 + shasum -a 1 ${file} | awk '{print $1}' > ${file}.sha1 + shasum -a 256 ${file} | awk '{print $1}' > ${file}.sha256 + shasum -a 512 ${file} | awk '{print $1}' > ${file}.sha512 + # Generate checksums for the signature file + md5 ${file}.asc | awk '{print $NF}' > ${file}.asc.md5 + shasum -a 1 ${file}.asc | awk '{print $1}' > ${file}.asc.sha1 + shasum -a 256 ${file}.asc | awk '{print $1}' > ${file}.asc.sha256 + shasum -a 512 ${file}.asc | awk '{print $1}' > ${file}.asc.sha512 + fi + done + + # Verify signature files were created + echo "Signature files created:" + ls -l ${{ env.DOWNLOAD_DIR }}/*.sig | awk '{ $3=""; $4=""; print }' || echo "No signature files found" + + - name: Create signing summary + run: | + echo "## Signing Summary" >> $GITHUB_STEP_SUMMARY + echo "Signed artifacts for \`${{ env.S3_PATH }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Signed Files:" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + ls -l ${{ env.DOWNLOAD_DIR }} | awk '{ $3=""; $4=""; print }' >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + + - name: Gzip files + run: | + rm -f trident-${{ inputs.project_version }}-bundle.zip + zip -r trident-${{ inputs.project_version }}-bundle.zip ${DOWNLOAD_DIR} + LOCAL_MD5=$(md5sum trident-${{ inputs.project_version }}-bundle.zip | awk '{print $1}') + echo "trident-${{ inputs.project_version }}-bundle.zip: $LOCAL_MD5" + + - name: Upload signed artifacts + uses: actions/upload-artifact@v4 + with: + name: trident-${{ inputs.project_version }}-bundle.zip + path: "./trident-${{ inputs.project_version }}-bundle.zip" + if-no-files-found: error + + upload-signed-to-s3: + name: Upload Signed Artifacts to S3 + runs-on: ubuntu-22.04 + needs: download-from-s3-and-sign + + permissions: + actions: read + contents: read + id-token: write # Needed for AWS credential provider + + steps: + - name: Download signed artifacts + uses: actions/download-artifact@v4 + with: + name: trident-${{ inputs.project_version }}-bundle.zip + path: ./signed-artifacts/ + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN_TEST_UPLOAD }} # 👈 replace with your IAM role + aws-region: ${{ secrets.AWS_REGION }} + + - name: Upload signed artifacts to S3 + run: | + S3_SIGNED_PATH="s3://${{ secrets.S3_BUCKET_TEST }}" + if [ -n "${{ secrets.S3_PREFIX }}" ]; then + S3_SIGNED_PATH="$S3_SIGNED_PATH/${{ secrets.S3_PREFIX }}" + fi + S3_SIGNED_PATH="$S3_SIGNED_PATH/${{ inputs.project_version }}" + echo "Uploading signed artifacts to $S3_SIGNED_PATH" + aws s3 cp "./signed-artifacts/" "$S3_SIGNED_PATH" --recursive + echo "Upload of signed artifacts to S3 completed successfully" + + echo "## MD5 Summary of Uploaded Files" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Filename | MD5 Hash |" >> $GITHUB_STEP_SUMMARY + echo "|----------|----------|" >> $GITHUB_STEP_SUMMARY + for file in ./signed-artifacts/*; do + if [ -f "$file" ]; then + FILENAME=$(basename "$file") + LOCAL_MD5=$(md5sum $file | awk '{print $1}') + echo "| $FILENAME | $LOCAL_MD5 |" >> $GITHUB_STEP_SUMMARY + echo "$FILENAME: $LOCAL_MD5" + fi + done \ No newline at end of file diff --git a/build.gradle b/build.gradle index ea18bee1..7ecfdaf9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ -def VERSION = '0.11.0' -group 'io.github.tronprotocol' +def DEFAULT_VERSION = '0.11.0' +def DEFAULT_GROUP = 'io.github.tronprotocol' buildscript { repositories { @@ -36,7 +36,9 @@ ext { } allprojects { - version = VERSION + version = project.hasProperty("VERSION") ? project.property("VERSION") : DEFAULT_VERSION + group = project.hasProperty("GROUP") ? project.property("GROUP") : DEFAULT_GROUP + repositories { mavenCentral() @@ -168,20 +170,17 @@ javadoc { tasks.register('javadocJar', Jar) { archiveClassifier = 'javadoc' - archiveVersion = VERSION from javadoc } tasks.register('sourcesJar', Jar) { archiveClassifier = 'sources' - archiveVersion = VERSION from subprojects.collect { project -> project.sourceSets.main.allSource } } tasks.register('buildLib', Jar) { - archiveVersion = VERSION from subprojects.collect { project -> project.sourceSets.main.output }