Merge pull request #893 from fortify/release-please--branches--rel/v3.x #2835
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and release | |
| on: | |
| workflow_dispatch: | |
| pull_request: | |
| push: | |
| branches: | |
| - '**' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| native_image_opts: --verbose -H:Log=registerResource:verbose -H:+PrintClassInitialization -march=compatibility | |
| graal_distribution: graalvm-community | |
| graal_java_version: 21 | |
| jobs: | |
| build: | |
| name: Build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check-out source code | |
| uses: actions/checkout@v4 | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| - name: PROD - Prepare GitHub release | |
| id: create_prod_release | |
| uses: googleapis/release-please-action@v4 | |
| if: contains(github.ref, 'refs/heads/rel/') | |
| with: | |
| skip-github-pull-request: true | |
| target-branch: ${{ github.ref_name }} | |
| release-type: simple | |
| - name: PROD - Define release info | |
| if: steps.create_prod_release.outputs.release_created | |
| run: | | |
| tag=${{steps.create_prod_release.outputs.tag_name}} | |
| version=${{steps.create_prod_release.outputs.version}} | |
| major=${{steps.create_prod_release.outputs.major}} | |
| minor=${{steps.create_prod_release.outputs.minor}} | |
| patch=${{steps.create_prod_release.outputs.patch}} | |
| echo DO_BUILD=true >> $GITHUB_ENV | |
| echo DO_RELEASE=true >> $GITHUB_ENV | |
| echo DO_PROD_RELEASE=true >> $GITHUB_ENV | |
| echo RELEASE_TAG=${tag} >> $GITHUB_ENV | |
| echo RELEASE_VERSION=${version} >> $GITHUB_ENV | |
| echo VERSION_MAJOR=${major} >> $GITHUB_ENV | |
| echo VERSION_MINOR=${minor} >> $GITHUB_ENV | |
| echo VERSION_PATCH=${patch} >> $GITHUB_ENV | |
| - name: DEV - Define release info | |
| if: (startsWith(github.ref, 'refs/heads/') || github.event_name == 'pull_request') && !env.DO_PROD_RELEASE | |
| run: | | |
| # For pull_request events, use head_ref (source branch); for push/workflow_dispatch, extract from ref | |
| if [ "${{ github.event_name }}" == "pull_request" ]; then | |
| branch="${{ github.head_ref }}" | |
| else | |
| branch="${GITHUB_REF#refs/heads/}" | |
| fi | |
| tag="dev_${branch//[^a-zA-Z0-9_.-]/.}" # Replace all special characters by a dot | |
| tag="${tag//dev_dev./dev_}" # Remove duplicate dev-prefix | |
| tag="${tag//dev_rel./dev_}" # Remove rel-prefix | |
| major="0" | |
| minor="$(date +'%Y%m%d')" | |
| patch="$(date +'%H%M%S')-$tag" | |
| version="${major}.${minor}.${patch}" | |
| echo DO_BUILD=true >> $GITHUB_ENV # We always want to do a build if we're building a branch | |
| echo BRANCH=${branch} >> $GITHUB_ENV | |
| echo RELEASE_TAG=${tag} >> $GITHUB_ENV | |
| echo RELEASE_VERSION=${version} >> $GITHUB_ENV | |
| echo VERSION_MAJOR=${major} >> $GITHUB_ENV | |
| echo VERSION_MINOR=${minor} >> $GITHUB_ENV | |
| echo VERSION_PATCH=${patch} >> $GITHUB_ENV | |
| if git ls-remote --exit-code origin refs/tags/${tag} >/dev/null 2>&1; then | |
| echo "Found tag ${tag}, development release will be published" | |
| echo DO_RELEASE=true >> $GITHUB_ENV | |
| echo DO_DEV_RELEASE=true >> $GITHUB_ENV | |
| else | |
| echo "Tag ${tag} does not exist, no development release will be published" | |
| fi | |
| - name: Build release ${{env.RELEASE_VERSION}} | |
| if: env.DO_BUILD | |
| run: ./gradlew clean build dist distThirdPartyReleaseAsset distFtest -Pversion=${{env.RELEASE_VERSION}} -PautoFormat=false | |
| - name: Check fcli version | |
| if: env.DO_BUILD | |
| run: java -jar build/libs/fcli.jar --version | tee /dev/stderr | grep -E '[0-9]+\.[0-9]+\.[0-9]+' >/dev/null || (echo "fcli --version doesn't output proper version number"; exit 1) | |
| - name: Publish build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-output | |
| path: build/dist/**/* | |
| outputs: | |
| do_release: ${{ env.DO_RELEASE }} | |
| do_prod_release: ${{ env.DO_PROD_RELEASE }} | |
| do_dev_release: ${{ env.DO_DEV_RELEASE }} | |
| release_tag: ${{ env.RELEASE_TAG }} | |
| release_version: ${{ env.RELEASE_VERSION }} | |
| version_major: ${{ env.VERSION_MAJOR }} | |
| version_minor: ${{ env.VERSION_MINOR }} | |
| version_patch: ${{ env.VERSION_PATCH }} | |
| branch: ${{ env.BRANCH }} | |
| native_linux: | |
| name: native-image-linux | |
| needs: build | |
| runs-on: ubuntu-22.04 | |
| # env: | |
| # TOOLCHAIN_BASE: /opt/musl_cc | |
| # TOOLCHAIN_DIR: /opt/musl_cc/x86_64-linux-musl-native | |
| # CC: /opt/musl_cc/x86_64-linux-musl-native/bin/gcc | |
| steps: | |
| - name: Check-out source code | |
| uses: actions/checkout@v4 | |
| - uses: graalvm/setup-graalvm@v1 | |
| with: | |
| distribution: ${{ env.graal_distribution }} | |
| java-version: ${{ env.graal_java_version }} | |
| native-image-musl: true | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| name: build-output | |
| # For Linux, we build a statically linked native image, to allow for building a 'FROM scratch' | |
| # Docker image, and to avoid libc version issues. Since Jansi is not supported on statically | |
| # linked images (see https://github.com/fusesource/jansi/issues/246), we set a system property | |
| # to indicate that FortifyCLI shouldn't try to invoke AnsiConsole::systemInstall/Uninstall. In | |
| # order for FortifyCLI to be able to see this system property, we need to initialize this class | |
| # at build time (see https://www.graalvm.org/22.1/reference-manual/native-image/Properties/). | |
| # We also exclude the native Jansi library resources, as these are now no longer needed. | |
| - name: Create native fcli | |
| run: native-image ${{ env.native_image_opts }} --static --libc=musl -Djansi.disable=true --initialize-at-build-time=com.fortify.cli.common.util.JAnsiConfig -H:ExcludeResources="org/fusesource/jansi/internal/native/.*" -jar ./artifacts/release-assets/fcli.jar fcli | |
| - name: Compress native fcli | |
| uses: svenstaro/upx-action@v2 | |
| with: | |
| files: fcli | |
| - name: Basic test of native fcli | |
| run: ./fcli --help && ./fcli get --help && ./fcli action help ci | |
| - name: Check fcli version | |
| run: ./fcli --version | tee /dev/stderr | grep -E '[0-9]+\.[0-9]+\.[0-9]+' >/dev/null || (echo "fcli --version doesn't output proper version number"; exit 1) | |
| - name: Package native fcli | |
| run: tar -zcvf artifacts/release-assets/fcli-linux.tgz fcli -C ./artifacts fcli_completion | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| path: ./artifacts/**/fcli-linux.tgz | |
| name: fcli-linux | |
| native_mac: | |
| name: native-image-mac | |
| needs: build | |
| runs-on: macos-latest | |
| steps: | |
| - name: Check-out source code | |
| uses: actions/checkout@v4 | |
| - uses: graalvm/setup-graalvm@v1 | |
| with: | |
| distribution: ${{ env.graal_distribution }} | |
| java-version: ${{ env.graal_java_version }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| name: build-output | |
| # For MacOS, we build a dynamically linked image. Jansi by default provides a resource-config.json | |
| # file to include native libraries for all platforms; we override this to include only the MacOS | |
| # libraries | |
| - name: Create native fcli | |
| run: native-image ${{ env.native_image_opts }} -march=compatibility -H:ExcludeResources="org/fusesource/jansi/internal/native/Windows/.*" -H:ExcludeResources="org/fusesource/jansi/internal/native/Linux/.*" -H:ExcludeResources="org/fusesource/jansi/internal/native/FreeBSD/.*" -jar ./artifacts/release-assets/fcli.jar fcli | |
| # Disabled for now, as compressed binaries crash on macOS Ventura or above | |
| #- name: Compress native fcli | |
| # uses: svenstaro/upx-action@v2 | |
| # with: | |
| # files: fcli | |
| - name: Basic test of native fcli | |
| run: ./fcli --help && ./fcli get --help && ./fcli action help ci | |
| - name: Package native fcli | |
| run: tar -zcvf ./artifacts/release-assets/fcli-mac.tgz fcli -C ./artifacts fcli_completion | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| path: ./artifacts/**/fcli-mac.tgz | |
| name: fcli-mac | |
| native_win: | |
| name: native-image-win | |
| needs: build | |
| runs-on: windows-2022 | |
| steps: | |
| - uses: graalvm/setup-graalvm@v1 | |
| with: | |
| distribution: ${{ env.graal_distribution }} | |
| java-version: ${{ env.graal_java_version }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| name: build-output | |
| # For Windows, we build a dynamically linked image. Jansi by default provides a resource-config.json | |
| # file to include native libraries for all platforms; we override this to include only the 64-bit | |
| # Windows library | |
| - name: Create native fcli | |
| run: >- | |
| "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" && | |
| ${{ env.JAVA_HOME }}\bin\native-image.cmd ${{ env.native_image_opts }} -H:ExcludeResources="org/fusesource/jansi/internal/native/Mac/.*" -H:ExcludeResources="org/fusesource/jansi/internal/native/Linux/.*" -H:ExcludeResources="org/fusesource/jansi/internal/native/FreeBSD/.*" -jar .\artifacts\release-assets\fcli.jar fcli | |
| shell: cmd | |
| # We don't compress the Windows binary for now as this is incompatible with current Graal version. | |
| # See https://github.com/fortify/fcli/issues/148 | |
| # - name: Compress native fcli | |
| # uses: svenstaro/upx-action@v2 | |
| # with: | |
| # files: fcli.exe | |
| - name: Basic test of native fcli | |
| run: | | |
| .\fcli.exe --help | |
| .\fcli.exe get --help | |
| .\fcli.exe action help ci | |
| - name: Package native fcli | |
| run: 7z a artifacts\release-assets\fcli-windows.zip fcli*.exe | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| path: ./artifacts/**/fcli-windows.zip | |
| name: fcli-windows | |
| combine-artifacts: | |
| needs: [build, native_linux, native_mac, native_win] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| merge-multiple: true | |
| - run: | | |
| cd ./artifacts/release-assets | |
| for f in *; do | |
| sha256sum ${f} > ${f}.sha256 | |
| done | |
| if [ -z "$SIGN_KEY" ] || [ -z "$SIGN_PASSPHRASE" ]; then | |
| echo "Signatures for fcli artifacts haven't been calculated; SIGN_KEY and/or SIGN_PASSPHRASE secrets not present" | |
| else | |
| for f in *; do | |
| openssl dgst -sha256 -passin env:SIGN_PASSPHRASE -sign <(echo "${SIGN_KEY}") -out ${f}.rsa_sha256 ${f} | |
| done | |
| fi | |
| env: | |
| SIGN_PASSPHRASE: ${{ secrets.SIGN_PASSPHRASE }} | |
| SIGN_KEY: ${{ secrets.SIGN_KEY }} | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| name: combined-artifacts | |
| ftest: | |
| name: Trigger functional tests | |
| needs: [build, native_linux, native_mac, native_win, combine-artifacts] | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Previously we had a workflow_run trigger on functional-tests.yaml, but: | |
| # - This approach allows for starting functional tests a bit earlier (no need to wait for Docker builds) | |
| # - The workflow_run trigger executes the workflow file from the default branch, whereas this approach | |
| # allows for running the workflow file from the same branch as the ci workflow. | |
| - name: Check-out source code | |
| uses: actions/checkout@v4 | |
| - run: | | |
| # Use branch output from build job if available, otherwise fall back to GITHUB_REF | |
| if [ -n "${{ needs.build.outputs.branch }}" ]; then | |
| ref="${{ needs.build.outputs.branch }}" | |
| else | |
| ref="${GITHUB_REF}" | |
| fi | |
| gh workflow run functional-tests.yml --ref "${ref}" -f runId=${GITHUB_RUN_ID} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| release: | |
| name: release | |
| if: needs.build.outputs.do_release | |
| needs: [build, native_linux, native_mac, native_win, combine-artifacts] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check-out source code | |
| uses: actions/checkout@v4 | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| name: combined-artifacts | |
| - name: PROD - Prepare release PR | |
| if: contains(github.ref, 'refs/heads/rel/') | |
| uses: googleapis/release-please-action@v4 | |
| with: | |
| skip-github-release: true | |
| target-branch: ${{ github.ref_name }} | |
| release-type: simple | |
| - name: DEV - Prepare GitHub release | |
| if: needs.build.outputs.do_dev_release | |
| run: | | |
| gh release delete ${{ needs.build.outputs.release_tag }} -y || true | |
| gh release create ${{ needs.build.outputs.release_tag }} -p -t "Development Release - ${{ needs.build.outputs.branch }} branch" -n 'See `Assets` section below for latest build artifacts' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: DEV - Update ${{ needs.build.outputs.release_tag }} tag | |
| uses: richardsimko/update-tag@v1 | |
| if: needs.build.outputs.do_dev_release | |
| with: | |
| tag_name: ${{ needs.build.outputs.release_tag }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload assets to release | |
| if: needs.build.outputs.do_release | |
| run: | | |
| files=$(find "./artifacts/release-assets" -type f -printf "%p ") | |
| gh release upload "${{ needs.build.outputs.release_tag }}" $files --clobber | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| semantic_versions: | |
| name: Publish semantic versions | |
| if: needs.build.outputs.do_prod_release | |
| needs: [build, native_linux, native_mac, native_win, combine-artifacts, release] | |
| strategy: | |
| matrix: | |
| semantic_version: | |
| - v${{needs.build.outputs.version_major}}.${{needs.build.outputs.version_minor}} | |
| - v${{needs.build.outputs.version_major}} | |
| # TODO If we publish a feature/patch for an older major version, | |
| # for example from the rel/v2.x branch, | |
| # this may cause the older major version to be tagged as 'latest' | |
| - latest | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check-out source code | |
| uses: actions/checkout@v4 | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| name: combined-artifacts | |
| - name: PROD - Publish ${{ matrix.semantic_version }} tag | |
| uses: richardsimko/update-tag@v1 | |
| with: | |
| tag_name: ${{ matrix.semantic_version }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: PROD - Publish semantic release ${{ matrix.semantic_version }} | |
| run: | | |
| gh release delete ${{ matrix.semantic_version }} -y || true | |
| gh release create ${{ matrix.semantic_version }} -t "${{ matrix.semantic_version }}" -n "Semantic version release for [${{ needs.build.outputs.release_tag }}](https://github.com/fortify/fcli/releases/tag/${{ needs.build.outputs.release_tag }})" --verify-tag --latest=false | |
| files=$(find "./artifacts/release-assets" -type f -printf "%p ") | |
| gh release upload "${{ matrix.semantic_version }}" $files --clobber | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| docker: | |
| name: Trigger Docker builds | |
| needs: [build, release, semantic_versions] | |
| # Always run if build & release were successful, ignoring status of semantic_versions | |
| if: always() && needs.build.result == 'success' && needs.release.result == 'success' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Trigger Docker image builds in fcli-docker repository | |
| run: | | |
| gh workflow run docker.yml \ | |
| --repo fortify/fcli-docker \ | |
| --ref main \ | |
| -f "releaseTag=${{ needs.build.outputs.release_tag }}" \ | |
| -f "doPublish=${{ needs.build.outputs.do_release }}" \ | |
| -f "isLatest=${{ needs.build.outputs.do_prod_release }}" | |
| echo "✓ Docker build triggered in fortify/fcli-docker repository" | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.FCLI_DOCKER_TRIGGER_TOKEN }} | |
| publishPages: | |
| name: publishPages | |
| if: needs.build.outputs.do_release | |
| needs: [build] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check-out existing docs from gh-pages branch | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: gh-pages | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./tmp | |
| name: build-output | |
| - name: Update documentation from artifact | |
| run: | | |
| # Extract top-level documentation resources | |
| # TODO Should we do this only when building a release, or also for dev_v3.x, | |
| # or for all (dev & release) versions like we do now? | |
| unzip -o tmp/docs-gh-pages-static.zip -d "." | |
| # Define the output directory, based on tag/branch name | |
| versionDir=${{ needs.build.outputs.release_tag }} | |
| # Delete, recreate and fill the directory for the current tag/branch name, | |
| # while leaving documentation for other tags/branches intact (as checked out above) | |
| rm -rf "${versionDir}" | |
| mkdir -p "${versionDir}" | |
| unzip tmp/docs-gh-pages-versioned.zip -d "${versionDir}" | |
| # Update symlinks based on available versions, processing versions in ascending order | |
| # to replace previous links with a newer version if appropriate. For example, 'latest' | |
| # will first point to the oldest version, then replaced with second-oldest version, ..., | |
| # until it points to the latest version. | |
| ls -d v*.*.* | sort -V | while read line; do | |
| ln -sfT $line latest | |
| ln -sfT $line $(echo "$line" | cut -d. -f 1) # v<major> | |
| ln -sfT $line $(echo "$line" | cut -d. -f 1,2) # v<major>.<minor> | |
| done | |
| # Same for dev_*, but only generating latest_dev symlink | |
| ls -d dev_* | sort -V | while read line; do | |
| ln -sfT $line latest_dev | |
| done | |
| # Recreate version data files, which may be empty if no versions available | |
| mkdir -p _data/versions | |
| touch _data/versions/release.yml | |
| touch _data/versions/dev.yml | |
| ls -d v*.*.* | sort -rV | while read line; do echo "- '$line'"; done > _data/versions/release.yml | |
| ls -d dev_* | sort | while read line; do echo "- '$line'"; done > _data/versions/dev.yml | |
| git config user.name github-actions | |
| git config user.email github-actions@fortify.com | |
| git add . | |
| git commit -m "Update documentation for ${{ needs.build.outputs.release_tag }}" | |
| git push | |