From 4f2a1b1c295d3fa0dbcc90f92c1c01893d20f5e1 Mon Sep 17 00:00:00 2001 From: Maurizio Turatti Date: Mon, 4 Nov 2024 12:08:34 +0100 Subject: [PATCH] Add GitHub Actions workflow for stable release process --- .github/workflows/native-image-release.yml | 213 ++++++++++++++++++ ...ve-image.yml => native-image-snapshot.yml} | 0 .github/workflows/tags.yml | 181 +++++++++++++++ 3 files changed, 394 insertions(+) create mode 100644 .github/workflows/native-image-release.yml rename .github/workflows/{native-image.yml => native-image-snapshot.yml} (100%) create mode 100644 .github/workflows/tags.yml diff --git a/.github/workflows/native-image-release.yml b/.github/workflows/native-image-release.yml new file mode 100644 index 000000000..39206da8f --- /dev/null +++ b/.github/workflows/native-image-release.yml @@ -0,0 +1,213 @@ +name: Native Image Release + +on: + # Triggered by other workflows using workflow_call + workflow_call: + inputs: + version: + description: "Version to release" + required: true + type: string + # Also allow manual triggering + workflow_dispatch: + inputs: + version: + description: "Version to release" + required: true + type: string + +jobs: + build-and-upload: + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + arch: linux-amd64 + - os: windows-latest + arch: windows-amd64 + - os: macos-13 + arch: "darwin-amd64" + - os: macos-latest + arch: "darwin-arm64" + timeout-minutes: 20 + outputs: + ubuntu: ${{ steps.set-output.outputs.ubuntu }} + steps: + - uses: actions/checkout@v4 + + - uses: graalvm/setup-graalvm@v1 + with: + java-version: "21" + distribution: "graalvm-community" + github-token: ${{ secrets.GITHUB_TOKEN }} + cache: "maven" + native-image-job-reports: "true" + + - name: Build MacOS Intel native + if: matrix.arch == 'darwin-amd64' + run: | + echo "GRAALVM_HOME: $GRAALVM_HOME" + echo "JAVA_HOME: $JAVA_HOME" + java --version + native-image -march=list + mvn package -Pnative -DskipTests -Dnative.march="-march=x86-64" + + - name: Build MacOS Apple Silicon native + if: matrix.arch == 'darwin-arm64' + run: | + echo "GRAALVM_HOME: $GRAALVM_HOME" + echo "JAVA_HOME: $JAVA_HOME" + java --version + native-image -march=list + mvn package -Pnative -DskipTests -Dnative.march="-march=armv8-a" + + - name: Build Windows native + if: matrix.arch == 'windows-amd64' + run: | + echo "GRAALVM_HOME: %GRAALVM_HOME%" + echo "JAVA_HOME: %JAVA_HOME%" + java --version + native-image.cmd -march=list + mvn package -Pnative -DskipTests "-Dnative.march=-march=x86-64" + + - name: Build Linux native + if: matrix.arch == 'linux-amd64' + run: | + echo "GRAALVM_HOME: $GRAALVM_HOME" + echo "JAVA_HOME: $JAVA_HOME" + java --version + native-image -march=list + mvn package -Pnative -DskipTests -Dnative.march="-march=x86-64" + chmod +x core/target/restheart + + - name: Upload restheart-${{ matrix.arch }} native artifact + uses: actions/upload-artifact@v4 + with: + name: restheart-${{ matrix.arch }} + path: ${{ matrix.arch == 'windows-amd64' && 'core/target/restheart.exe' || 'core/target/restheart' }} + overwrite: true + + - name: Upload restheart-${{ matrix.arch }} to Release + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs').promises; + + const isWindows = '${{ matrix.os }}' === 'windows-latest'; + const filePath = isWindows ? 'core/target/restheart.exe' : 'core/target/restheart'; + const fileName = `restheart-${{ matrix.arch }}${isWindows ? '.exe' : ''}`; + const releaseTag = '${{ inputs.version }}'; // Use the passed version input + + try { + const content = await fs.readFile(filePath); + + const { data: releases } = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo + }); + + const release = releases.find(r => r.tag_name === releaseTag); + + if (!release) { + throw new Error(`Release with tag '${releaseTag}' not found.`); + } + + // Check if an asset with the same name exists in the release + const existingAsset = release.assets.find(asset => asset.name === fileName); + + if (existingAsset) { + console.log(`Asset ${fileName} already exists. Deleting it...`); + + // Delete the existing asset + await github.rest.repos.deleteReleaseAsset({ + owner: context.repo.owner, + repo: context.repo.repo, + asset_id: existingAsset.id + }); + + console.log(`Deleted asset ${fileName}`); + } + + console.log(`Uploading ${fileName} to release ${releaseTag}...`); + await github.rest.repos.uploadReleaseAsset({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + name: fileName, + data: content, + headers: { + 'content-type': 'application/octet-stream' + } + }); + + console.log(`Successfully uploaded ${fileName} to release ${releaseTag}`); + } catch (error) { + console.error('Error occurred:', error.message); + process.exit(1); + } + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Set Output for docker-publish-linux Job + if: matrix.arch == 'linux-amd64' + id: set-output + run: echo "ubuntu=true" >> $GITHUB_OUTPUT + + docker-publish-linux: + runs-on: ubuntu-latest + needs: build-and-upload + if: needs.build-and-upload.outputs.ubuntu == 'true' + steps: + - uses: actions/checkout@v4 + + - name: Download Binary Artifact + uses: actions/download-artifact@v4 + with: + name: restheart-linux-amd64 + path: core/target/restheart + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Extract Version Components + id: extract_version + run: | + MAJOR=$(echo "${{ inputs.version }}" | cut -d '.' -f 1) + MINOR=$(echo "${{ inputs.version }}" | cut -d '.' -f 2) + PATCH=$(echo "${{ inputs.version }}" | cut -d '.' -f 3) + + # Export the major, minor, and patch versions as environment variables + echo "MAJOR=$MAJOR" >> $GITHUB_ENV + echo "MINOR=$MINOR" >> $GITHUB_ENV + echo "PATCH=$PATCH" >> $GITHUB_ENV + + - name: Build Docker Tags + id: build_tags + run: | + # Construct all tags based on the MAJOR.MINOR.PATCH format + TAGS="softinstigate/restheart:latest-native,softinstigate/restheart:${{ env.MAJOR }}-native,softinstigate/restheart:${{ env.MAJOR }}.${{ env.MINOR }}-native,softinstigate/restheart:${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }}-native" + echo "TAGS=$TAGS" >> $GITHUB_ENV + + - name: Build and Push multi-arch native Docker images + uses: docker/build-push-action@v6 + with: + context: ./core/ + file: ./core/Dockerfile.native + platforms: | + linux/amd64, + linux/arm64, + linux/ppc64le, + linux/s390x + push: true + pull: true + tags: ${{ env.TAGS }} diff --git a/.github/workflows/native-image.yml b/.github/workflows/native-image-snapshot.yml similarity index 100% rename from .github/workflows/native-image.yml rename to .github/workflows/native-image-snapshot.yml diff --git a/.github/workflows/tags.yml b/.github/workflows/tags.yml new file mode 100644 index 000000000..e51e09e54 --- /dev/null +++ b/.github/workflows/tags.yml @@ -0,0 +1,181 @@ +name: Stable Release + +on: + push: + branches: + - "!master" # Ignore the master branch + tags: + - "*" # Trigger on any tag + +jobs: + # Build and test the project + build: + if: "!contains(github.event.head_commit.message, 'skip ci')" + runs-on: ubuntu-latest + strategy: + matrix: + mongodb-version: ["5.0", "6.0"] + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "21" + cache: "maven" + + - name: Build and Test + run: | + mvn -B clean verify -Dmongodb.version="${{ matrix.mongodb-version }}" + + # Deploy the project to Maven Central and DockerHub + deploy: + if: "!contains(github.event.head_commit.message, 'skip ci')" + runs-on: ubuntu-latest + strategy: + matrix: + mongodb-version: ["7.0"] + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "21" + cache: "maven" + + - name: Build and Test + run: mvn -B clean verify -Dmongodb.version="${{ matrix.mongodb-version }}" + + - name: Import private gpg key + run: | + printf "%s" "$GPG_PRIVATE_KEY" > private.key + gpg --pinentry-mode=loopback --batch --yes --fast-import private.key + continue-on-error: true + env: + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + + - name: Deploy to Maven Central + continue-on-error: true + run: | + MAVEN_OPTS="--add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED" \ + mvn -B deploy -Pdeploy -DskipTests -Dmongodb.version="${{ matrix.mongodb-version }}" -s settings.xml + env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Set VERSION + id: vars + run: | + VERSION=${GITHUB_REF#refs/tags/} + echo "VERSION=$VERSION" >> $GITHUB_ENV + + - name: Extract Version Components + id: extract_version + run: | + MAJOR=$(echo "${{ env.VERSION }}" | cut -d '.' -f 1) + MINOR=$(echo "${{ env.VERSION }}" | cut -d '.' -f 2) + PATCH=$(echo "${{ env.VERSION }}" | cut -d '.' -f 3) + + # Export the major, minor, and patch versions as environment variables + echo "MAJOR=$MAJOR" >> $GITHUB_ENV + echo "MINOR=$MINOR" >> $GITHUB_ENV + echo "PATCH=$PATCH" >> $GITHUB_ENV + + - name: Set Docker Tags for standard images + id: set_tags + run: | + # Construct all tags based on the MAJOR.MINOR.PATCH format + TAGS="softinstigate/restheart:latest,softinstigate/restheart:${{ env.MAJOR }},softinstigate/restheart:${{ env.MAJOR }}.${{ env.MINOR }},softinstigate/restheart:${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }}" + echo "TAGS=$TAGS" >> $GITHUB_ENV + + - name: Build and Push multi-arch Docker images + uses: docker/build-push-action@v6 + with: + context: ./core/ + platforms: | + linux/amd64, + linux/arm64, + linux/ppc64le, + linux/s390x + push: true # push all images built + pull: true # pull all required images before building + tags: ${{ env.TAGS }} + + - name: Set Docker Tags for GraalVM image + id: set_graalvm_tags + run: | + # Construct all tags based on the MAJOR.MINOR.PATCH format + TAGS_GRAALVM="softinstigate/restheart:latest-graalvm,softinstigate/restheart:${{ env.MAJOR }}-graalvm,softinstigate/restheart:${{ env.MAJOR }}.${{ env.MINOR }}-graalvm,softinstigate/restheart:${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }}-graalvm" + echo "TAGS_GRAALVM=$TAGS_GRAALVM" >> $GITHUB_ENV + + - name: Build and Push GraalVM Docker image + uses: docker/build-push-action@v6 + with: + context: ./core/ + file: ./core/Dockerfile.graalvm + platforms: | + linux/amd64, + linux/arm64 + push: true # push all images built + pull: true # pull all required images before building + tags: ${{ env.TAGS_GRAALVM }} + + - name: Set Docker tags for Distroless image + id: set_distroless_tags + run: | + # Construct all tags based on the MAJOR.MINOR.PATCH format + TAGS_DISTROLESS="softinstigate/restheart:latest-distroless,softinstigate/restheart:${{ env.MAJOR }}-distroless,softinstigate/restheart:${{ env.MAJOR }}.${{ env.MINOR }}-distroless,softinstigate/restheart:${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }}-distroless" + echo "TAGS_DISTROLESS=$TAGS_DISTROLESS" >> $GITHUB_ENV + + - name: Build and Push distroless docker image + uses: docker/build-push-action@v6 + with: + context: ./core/ + file: ./core/Dockerfile.distroless + platforms: | + linux/amd64, + linux/arm64, + linux/ppc64le + push: true # push all images built + pull: true # pull all required images before building + tags: ${{ env.TAGS_DISTROLESS }} + + - name: Upload GitHub release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + body: | + # Release ${{ env.VERSION }} + files: | + core/target/restheart.tar.gz + core/target/restheart.zip + draft: true + prerelease: false + + # Separate job to call the reusable workflow + call-native-image-release: + if: "!contains(github.event.head_commit.message, 'skip ci')" + needs: deploy + uses: softinstigate/restheart/.github/workflows/native-image-release.yml@master + with: + version: "${{ env.VERSION }}"