Build, test & deploy #8071
Workflow file for this run
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
# | |
# SPDX-FileCopyrightText: 2023 Lifely | |
# SPDX-License-Identifier: EUPL-1.2+ | |
# | |
name: Build, test & deploy | |
on: | |
pull_request: | |
merge_group: | |
workflow_dispatch: | |
push: | |
branches: | |
- main | |
paths-ignore: | |
# ignore pushes to the publiccode.yaml file or else we would trigger an endless build loop | |
- 'publiccode.yaml' | |
# cancel any previous runs of this workflow for this branch that are still in progress | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref }} | |
cancel-in-progress: true | |
env: | |
JAVA_VERSION: '21' | |
CONTAINER_REGISTRY_URL: 'ghcr.io/infonl' | |
APPLICATION_NAME: 'zaakafhandelcomponent' | |
permissions: | |
contents: write | |
packages: write | |
checks: write | |
pull-requests: write | |
# Required for uploading SARIF reports | |
security-events: write | |
jobs: | |
paths-ignore: | |
runs-on: ubuntu-22.04 | |
outputs: | |
skip: ${{ steps.paths-ignore.outputs.skip }} | |
steps: | |
- name: Skip job when only Markdown files are changed | |
uses: kunitsucom/github-actions-paths-ignore-alternative@3800eba25a9d716029cd1db0439cb9194431cc5c # v0.0.4 | |
id: paths-ignore | |
with: | |
paths-ignore: |- | |
^.*\.md$ | |
^helm/ | |
build: | |
runs-on: ubuntu-22.04 | |
timeout-minutes: 30 | |
needs: paths-ignore | |
if: ${{ needs.paths-ignore.outputs.skip != 'true' || github.ref == 'refs/heads/main'}} | |
outputs: | |
branch_name: ${{ steps.gen_branch_name.outputs.BRANCH_NAME }} | |
build_number: ${{ steps.gen_build_number.outputs.BUILD_NUMBER }} | |
zac_docker_image: ${{ steps.gen_tag.outputs.ZAC_DOCKER_IMAGE }} | |
steps: | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
- name: Set branch name | |
id: gen_branch_name | |
run: echo "BRANCH_NAME=${{ github.ref_name }}" | sed 's/\//_/g; s/(//g; s/)//g' >> $GITHUB_OUTPUT | |
- name: Set build number | |
id: gen_build_number | |
run: echo "BUILD_NUMBER=${{ steps.gen_branch_name.outputs.BRANCH_NAME }}-${{ github.run_number }}" >> $GITHUB_OUTPUT | |
- name: Set Docker image tag | |
id: gen_tag | |
run: echo "ZAC_DOCKER_IMAGE=${{ env.CONTAINER_REGISTRY_URL }}/${{ env.APPLICATION_NAME }}:${{ steps.gen_build_number.outputs.BUILD_NUMBER }}" >> $GITHUB_OUTPUT | |
- name: Setup JDK | |
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0 | |
with: | |
java-version: ${{ env.JAVA_VERSION }} | |
distribution: 'temurin' | |
# Use the Maven cache here so that Maven artefacts (Maven build is triggered from the Gradle build) are cached. | |
cache: 'maven' | |
- name: Setup Gradle | |
uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2 | |
- name: Validate Gradle wrapper | |
uses: gradle/actions/wrapper-validation@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2 | |
# The Gradle build also executes a Maven command to build the WildFly bootable JAR. | |
# Disable the Gradle Configuration Cache for now because we sometimes run into a similar issue to: | |
# https://github.com/diffplug/spotless/issues/651 | |
- name: Gradle build | |
run: ./gradlew build -x test --info --no-configuration-cache | |
- name: Cache Gradle build artefacts | |
uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
build | |
key: build-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Cache generated Java clients | |
uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
src/generated | |
key: generated-java-clients-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Cache built frontend artefacts | |
uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
src/main/app/dist/zaakafhandelcomponent | |
src/main/app/src/generated/types | |
key: built-frontend-artefacts-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Cache built ZAC JAR | |
uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
target/zaakafhandelcomponent.jar | |
key: zac-jar-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
run-unit-tests: | |
needs: [build, paths-ignore] | |
if: ${{ needs.paths-ignore.outputs.skip != 'true' || github.ref == 'refs/heads/main'}} | |
runs-on: ubuntu-22.04 | |
timeout-minutes: 30 | |
env: | |
READ_PACKAGES_USERNAME: $${{ vars.READ_PACKAGES_USERNAME }} | |
READ_PACKAGES_TOKEN: ${{ secrets.READ_PACKAGES_TOKEN }} | |
steps: | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
- name: Setup JDK | |
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0 | |
with: | |
java-version: ${{ env.JAVA_VERSION }} | |
distribution: 'temurin' | |
- name: Setup Gradle | |
uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2 | |
- name: Restore Gradle build artefacts | |
uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
build | |
key: build-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Restore built frontend artefacts | |
uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
build | |
key: built-frontend-artefacts-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Restore generated Java clients | |
uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
src/generated | |
key: generated-java-clients-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Run unit tests | |
run: ./gradlew -x processResources -x classes test --info | |
- name: Publish unit test results | |
uses: EnricoMi/publish-unit-test-result-action@170bf24d20d201b842d7a52403b73ed297e6645b # v2.18.0 | |
if: always() | |
with: | |
check_name: unit-test-results | |
files: | | |
build/test-results/**/*.xml | |
src/main/app/reports/*.xml | |
- name: Generate unit test code coverage report | |
run: ./gradlew -x compileJava -x processResources -x compileKotlin -x classes -x test -x itest -x npmRunBuild npmRunTestCoverage jacocoTestReport --info | |
- name: Upload unit test coverage report to Codecov | |
uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2 | |
with: | |
flags: unittests | |
env: | |
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
build-docker-image-and-run-itests: | |
needs: [build, paths-ignore] | |
if: ${{ needs.paths-ignore.outputs.skip != 'true' || github.ref == 'refs/heads/main'}} | |
runs-on: ubuntu-22.04 | |
timeout-minutes: 30 | |
env: | |
BUILD_NUMBER: ${{ needs.build.outputs.build_number }} | |
BRANCH_NAME: ${{ needs.build.outputs.branch_name }} | |
ZAC_DOCKER_IMAGE: ${{ needs.build.outputs.zac_docker_image }} | |
GIT_COMMIT_HASH: ${{ github.sha }} | |
BAG_API_CLIENT_MP_REST_URL: $${{ vars.BAG_API_CLIENT_MP_REST_URL }} | |
BAG_API_KEY: ${{ secrets.BAG_API_KEY }} | |
steps: | |
# workaround to avoid 'No space left on device' error | |
- name: Free Disk Space (Ubuntu) | |
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 | |
with: | |
tool-cache: true | |
# do not clean up Docker images since we need them | |
docker-images: false | |
# disable cleaning up large packages since this takes a long time | |
large-packages: false | |
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
- name: Setup JDK | |
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0 | |
with: | |
java-version: ${{ env.JAVA_VERSION }} | |
distribution: 'temurin' | |
- name: Setup Gradle | |
uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2 | |
- name: Restore built ZAC JAR | |
uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
target/zaakafhandelcomponent.jar | |
key: zac-jar-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0 | |
- name: Build Docker image | |
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 | |
with: | |
tags: ${{ env.ZAC_DOCKER_IMAGE }} | |
build-args: | | |
versionNumber=${{ env.BUILD_NUMBER }} | |
branchName=${{ env.BRANCH_NAME }} | |
commitHash=${{ env.GIT_COMMIT_HASH }} | |
context: . | |
load: true | |
push: false | |
# use GitHub Actions cache to speed up the build | |
cache-from: type=gha | |
cache-to: type=gha,mode=max | |
# Make sure this step is run _after_ we have built our ZAC Docker Image because | |
# we do not want the ZAC Docker image to be cached. | |
# See: https://github.com/ScribeMD/docker-cache/issues/532 | |
- name: Cache Docker images | |
uses: ScribeMD/docker-cache@fb28c93772363301b8d0a6072ce850224b73f74e # 0.5.0 | |
with: | |
key: docker-${{ runner.os }}-${{ hashFiles('docker-compose.yaml') }} | |
- name: Run integration tests | |
run: | | |
./gradlew -PzacDockerImage=${ZAC_DOCKER_IMAGE} \ | |
-x compileJava -x processResources -x compileKotlin -x classes -x buildDockerImage \ | |
itest --info | |
- name: Publish integration test results | |
uses: EnricoMi/publish-unit-test-result-action@170bf24d20d201b842d7a52403b73ed297e6645b # v2.18.0 | |
if: always() | |
with: | |
check_name: integration-test-results | |
files: | | |
build/test-results/itest/**/*.xml | |
# JaCoCo requires our Java class files to be able to generate a report | |
# so restore the Gradle build artefacts from the cache | |
- name: Restore Gradle build artefacts | |
uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: | | |
build | |
key: build-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Generate JaCoCo integration test code coverage report | |
run: ./gradlew jacocoIntegrationTestReport -x itest --info | |
- name: Upload integration test coverage report to Codecov | |
uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2 | |
with: | |
flags: integrationtests | |
env: | |
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
- name: Run Trivy vulnerability scanner | |
uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # 0.29.0 | |
with: | |
image-ref: '${{ env.ZAC_DOCKER_IMAGE }}' | |
format: 'sarif' | |
output: 'trivy-results.sarif' | |
# limit the severities even when using Sarif | |
# or else all vulnerabilities will be reported | |
limit-severities-for-sarif: true | |
severity: 'CRITICAL,HIGH' | |
env: | |
# skip downloading the Trivy databases since we update the Trivy cache regularly | |
# in another workflow | |
TRIVY_SKIP_DB_UPDATE: true | |
TRIVY_SKIP_JAVA_DB_UPDATE: true | |
- name: Upload Trivy scan results to GitHub Security tab | |
uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9 | |
with: | |
sarif_file: 'trivy-results.sarif' | |
- name: Save Docker Image | |
if: github.ref == 'refs/heads/main' | |
run: docker save --output docker-image.tar ${ZAC_DOCKER_IMAGE} | |
- name: Cache ZAC Docker Image | |
if: github.ref == 'refs/heads/main' | |
uses: actions/cache/save@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: docker-image.tar | |
key: docker-image-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
dependabot-auto-merge: | |
needs: [run-unit-tests, build-docker-image-and-run-itests] | |
runs-on: ubuntu-22.04 | |
if: github.actor == 'dependabot[bot]' | |
permissions: | |
pull-requests: write | |
contents: write | |
steps: | |
- uses: fastify/github-action-merge-dependabot@c3bde0759d4f24db16f7b250b2122bc2df57e817 # v3.11.0 | |
with: | |
# Our Dependabot PRs are not merged automatically because an automatically merged PR | |
# does not trigger our push workflow (and so no release would be made). | |
# see: https://github.com/fastify/github-action-merge-dependabot/issues/134 | |
approve-only: true | |
target: minor | |
next-version: | |
if: ${{ github.ref == 'refs/heads/main'}} | |
runs-on: ubuntu-22.04 | |
outputs: | |
version: ${{ steps.get-version.outputs.replaced }} | |
tag: ${{ steps.get-tag.outputs.new_tag }} | |
steps: | |
# Checkout the repository including tags | |
- name: Checkout | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
fetch-depth: 0 | |
# Determine the next semantic version based on the commit message tags | |
- name: Get next tag | |
id: get-tag | |
uses: anothrNick/github-tag-action@f278d49d30cdd8775cc3e7dd00b5ee11686ee297 # 1.71.0 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
PRERELEASE: false | |
DEFAULT_BUMP: patch | |
WITH_V: true | |
RELEASE_BRANCHES: main | |
- name: Get next version | |
id: get-version | |
uses: frabert/replace-string-action@b6828c5a4cb6371753ff873b0d1c4c4fbd9a63cb # v2.5 | |
with: | |
pattern: 'v(.*)' | |
string: ${{ steps.get-tag.outputs.new_tag }} | |
replace-with: '$1' | |
- name: Print new tag and version | |
run: | | |
echo "Next version: ${{ steps.get-version.outputs.replaced }}" | |
echo "Next version tag: ${{ steps.get-tag.outputs.new_tag }}" | |
push-docker-image: | |
needs: [build, run-unit-tests, build-docker-image-and-run-itests, next-version] | |
runs-on: ubuntu-22.04 | |
timeout-minutes: 30 | |
if: ${{ github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, 'update ghcr.io/infonl/zaakafhandelcomponent docker tag') }} | |
env: | |
ZAC_DOCKER_IMAGE: ${{ needs.build.outputs.zac_docker_image }} | |
NEXT_VERSION: ${{ needs.next-version.outputs.version }} | |
steps: | |
- name: Docker Login | |
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 | |
with: | |
registry: ${{ env.CONTAINER_REGISTRY_URL }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Restore Docker Image | |
uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 | |
with: | |
path: docker-image.tar | |
key: docker-image-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_number }} | |
- name: Load Docker Image | |
run: docker load --input docker-image.tar | |
- name: Tag Docker Image with 'latest' tag | |
run: docker tag ${ZAC_DOCKER_IMAGE} ${CONTAINER_REGISTRY_URL}/${APPLICATION_NAME}:latest | |
- name: Tag Docker Image with next version tag | |
if: env.NEXT_VERSION != '' | |
run: docker tag ${ZAC_DOCKER_IMAGE} ${CONTAINER_REGISTRY_URL}/${APPLICATION_NAME}:${NEXT_VERSION} | |
- name: Push Docker Image with all tags | |
run: docker push --all-tags ${CONTAINER_REGISTRY_URL}/${APPLICATION_NAME} | |
create-release: | |
needs: [next-version, push-docker-image] | |
if: github.ref == 'refs/heads/main' | |
runs-on: ubuntu-22.04 | |
env: | |
NEXT_VERSION: ${{ needs.next-version.outputs.version }} | |
NEXT_VERSION_TAG: ${{ needs.next-version.outputs.tag }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
fetch-depth: 0 | |
- name: Create or update GitHub release | |
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0 | |
with: | |
token: ${{ secrets.GITHUB_TOKEN }} | |
tag: ${{ env.NEXT_VERSION_TAG }} | |
name: ${{ env.APPLICATION_NAME }} ${{ env.NEXT_VERSION }} | |
body: | | |
This release contains the docker image ${{ env.APPLICATION_NAME }} ${{ env.NEXT_VERSION }}, which is available | |
at ${{ env.CONTAINER_REGISTRY_URL }}/${{ env.APPLICATION_NAME }}:${{ env.NEXT_VERSION }} | |
draft: false | |
prerelease: false | |
allowUpdates: true | |
makeLatest: true | |
generateReleaseNotes: true | |
update-publiccode-yml: | |
needs: [ next-version, create-release ] | |
if: github.ref == 'refs/heads/main' | |
runs-on: ubuntu-22.04 | |
env: | |
NEXT_VERSION: ${{ needs.next-version.outputs.version }} | |
steps: | |
# check out the repository with the private SSH key of the deploy key so that | |
# we can bypass the ruleset for the main branch | |
# see: https://github.com/sbellone/release-workflow-example for details | |
- name: Checkout | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
ssh-key: ${{ secrets.DEPLOY_KEY_BYPASS_RULESET_MAIN_PRIVATE_KEY }} | |
- name: Get current date | |
id: set-current-date | |
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT | |
- uses: elieahd/templater@f802bfce98073a045ad327cdc2c9857564fdfc07 # v1 | |
with: | |
template: 'scripts/file-templates/publiccode-yaml-template.yaml' | |
file: 'publiccode.yaml' | |
variables: ' | |
REPO_URL=${{ github.repositoryUrl }} | |
SOFTWARE_VERSION=${{ needs.next-version.outputs.version }} | |
REPO_CREATED_AT=${{ steps.set-current-date.outputs.date }}' | |
- name: Commit changes | |
run: | | |
git config --local user.email "action@github.com" | |
git config --local user.name "GitHub Action" | |
git add publiccode.yaml | |
git commit -m "${{ github.workflow }}" || echo "No changes to commit" | |
git push | |
trigger-provision: | |
needs: [push-docker-image] | |
runs-on: ubuntu-22.04 | |
timeout-minutes: 30 | |
if: github.ref == 'refs/heads/main' | |
steps: | |
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
with: | |
github-token: ${{ secrets.PROVISION_TOKEN }} | |
script: | | |
await github.rest.actions.createWorkflowDispatch({ | |
owner: 'infonl', | |
repo: 'dimpact-provisioning', | |
workflow_id: 'azure-provision-zaakafhandelcomponent.yml', | |
inputs: { | |
tag: '${{ github.ref_name }}-${{ github.run_number }}', | |
}, | |
ref: 'main' | |
}) |