Skip to content

Build, test & deploy #8071

Build, test & deploy

Build, test & deploy #8071

#
# 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'
})