Merge pull request #651 from fortify/develop #1935
This file contains 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: | |
push: | |
branches: | |
- '**' | |
env: | |
native_image_opts: --verbose -H:Log=registerResource:verbose -H:+PrintClassInitialization | |
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: github.ref == 'refs/heads/v2.x' | |
with: | |
skip-github-pull-request: true | |
target-branch: v2.x | |
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/') && !env.DO_PROD_RELEASE | |
run: | | |
branch="${GITHUB_REF#refs/heads/}" | |
tag="dev_${branch//[^a-zA-Z0-9_.-]/.}" # Replace all special characters by a dot | |
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}} | |
- 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 }} | |
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.app.FortifyCLI -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 | |
- 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 | |
- 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 | |
- 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 | |
for f in *; do | |
openssl dgst -sha256 -passin env:SIGN_PASSPHRASE -sign <(echo "${SIGN_KEY}") -out ${f}.rsa_sha256 ${f} | |
done | |
env: | |
SIGN_PASSPHRASE: ${{ secrets.SIGN_PASSPHRASE }} | |
SIGN_KEY: ${{ secrets.SIGN_KEY }} | |
- uses: actions/upload-artifact@v4 | |
with: | |
path: ./artifacts | |
name: combined-artifacts | |
# For now, we only publish fcli-scratch image, but we do build the other images just for testing | |
docker-linux: | |
needs: [build, native_linux] | |
runs-on: ubuntu-latest | |
env: | |
DOCKER_SRC: fcli-other/fcli-docker/linux | |
steps: | |
- name: Check-out source code | |
uses: actions/checkout@v4 | |
- name: Download artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
path: ./artifacts | |
name: fcli-linux | |
- name: Build & test Linux images | |
shell: bash | |
run: | | |
tar -zxvf ./artifacts/release-assets/fcli-linux.tgz -C ${DOCKER_SRC} | |
cd ${DOCKER_SRC} | |
for i in scratch alpine ubi9 | |
do | |
docker build . --target fcli-${i} -t fcli-${i} | |
mkdir ${PWD}/${i} | |
docker run --rm -u $(id -u):$(id -g) -v ${PWD}/${i}:/data fcli-${i} fcli tool sc-client install | |
test -f ${PWD}/${i}/fortify/tools/bin/scancentral | |
done | |
- name: Docker Login | |
if: needs.build.outputs.do_release | |
uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKER_USERNAME }} | |
password: ${{ secrets.DOCKER_PASSWORD }} | |
- name: DEV - Tag Linux images | |
if: needs.build.outputs.do_dev_release | |
shell: bash | |
run: | | |
docker tag fcli-scratch fortifydocker/fcli:${{needs.build.outputs.release_tag}} | |
- name: PROD - Tag Linux images | |
if: needs.build.outputs.do_prod_release | |
shell: bash | |
run: | | |
docker tag fcli-scratch fortifydocker/fcli:latest | |
docker tag fcli-scratch fortifydocker/fcli:${{needs.build.outputs.version_major}} | |
docker tag fcli-scratch fortifydocker/fcli:${{needs.build.outputs.version_major}}.${{needs.build.outputs.version_minor}} | |
docker tag fcli-scratch fortifydocker/fcli:${{needs.build.outputs.version_major}}.${{needs.build.outputs.version_minor}}.${{needs.build.outputs.version_patch}} | |
# TODO Should we sign the images as well? | |
- name: Publish Linux Docker images | |
if: needs.build.outputs.do_release | |
shell: bash | |
run: | | |
docker push --all-tags fortifydocker/fcli | |
# For now, we only publish fcli-scratch Linux image, but we do build the Windows images just for testing | |
docker-win: | |
needs: [build, native_win] | |
runs-on: windows-2022 | |
env: | |
DOCKER_SRC: fcli-other/fcli-docker/windows | |
steps: | |
- name: Check-out source code | |
uses: actions/checkout@v4 | |
- name: Download artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
path: ./artifacts | |
name: fcli-windows | |
- name: Build & test Windows images | |
shell: bash | |
run: | | |
unzip ./artifacts/release-assets/fcli-windows.zip -d ${DOCKER_SRC} | |
cd ${DOCKER_SRC} | |
for i in ltsc2022 | |
do | |
docker build . --target fcli-${i} -t fcli-${i} | |
# Following doesn't work yet, hence the echo statements instead of actually running these. | |
# Likely, we need to pass Windows-style paths to volume mappings in docker run command | |
mkdir ${PWD}/${i} | |
echo docker run --rm -v ${PWD}/${i}:/data fcli-${i} fcli tool sc-client install | |
echo test -f ${PWD}/${i}/fortify/tools/bin/scancentral | |
done | |
- name: DEV - Tag Windows images | |
if: needs.build.outputs.do_dev_release | |
shell: bash | |
run: | | |
docker tag fcli-ltsc2022 fortifydocker/fcli:${{needs.build.outputs.release_tag}} | |
- name: PROD - Tag Windows images | |
if: needs.build.outputs.do_prod_release | |
shell: bash | |
run: | | |
docker tag fcli-ltsc2022 fortifydocker/fcli:ltsc2022-latest | |
docker tag fcli-ltsc2022 fortifydocker/fcli:ltsc2022-${{needs.build.outputs.version_major}} | |
docker tag fcli-ltsc2022 fortifydocker/fcli:ltsc2022-${{needs.build.outputs.version_major}}.${{needs.build.outputs.version_minor}} | |
docker tag fcli-ltsc2022 fortifydocker/fcli:ltsc2022-${{needs.build.outputs.version_major}}.${{needs.build.outputs.version_minor}}.${{needs.build.outputs.version_patch}} | |
#- name: Docker Login | |
# if: needs.build.outputs.do_release | |
# uses: docker/login-action@v3 | |
# with: | |
# username: ${{ secrets.DOCKER_USERNAME }} | |
# password: ${{ secrets.DOCKER_PASSWORD }} | |
# TODO Should we sign the images as well? | |
#- name: Publish Linux Docker images | |
# if: needs.build.outputs.do_release | |
# shell: bash | |
# run: | | |
# docker push --all-tags fortifydocker/fcli | |
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: github.ref == 'refs/heads/v2.x' | |
uses: googleapis/release-please-action@v4 | |
with: | |
skip-github-release: true | |
release-type: simple | |
target-branch: v2.x | |
- 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 - ${GITHUB_REF#refs/heads/} 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 }} | |
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 | |
path: docs | |
- name: Download artifacts | |
uses: actions/download-artifact@v4 | |
with: | |
path: ./artifacts | |
name: build-output | |
- name: Update documentation from artifact | |
run: | | |
# Delete all Git-related files | |
rm -rf docs/.git* | |
# Extract top-level documentation resources | |
# TODO Should we do this only when building a release, or also for dev_v2.x, | |
# or for all (dev & release) versions like we do now? | |
unzip -o artifacts/docs-gh-pages.zip -d "docs" | |
# Define the output directory, based on tag/branch name | |
versionDir=docs/${{ 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 artifacts/docs-jekyll.zip -d "${versionDir}" | |
# Recreate version data files, which may be empty if no versions available | |
cd docs | |
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 | |
- name: Deploy documentation | |
uses: peaceiris/actions-gh-pages@v4 | |
with: | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
publish_dir: ./docs | |
enable_jekyll: true | |