Skip to content

Lazy and prefiltered OPTIONAL #7728

Lazy and prefiltered OPTIONAL

Lazy and prefiltered OPTIONAL #7728

Workflow file for this run

name: Docker build and publish
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
IMAGE: adfreiburg/qlever
concurrency:
# When this is not a pull request, then we want all the docker containers to be pushed, we therefore
# directly fall back to the commit hash which will be distinct for each push to master.
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.sha}}'
cancel-in-progress: true
# This workflow is heavily based on https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners .
jobs:
build:
strategy:
matrix:
include:
- platform: linux/amd64
runner: ubuntu-24.04
- platform: linux/arm64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v4
# Generate metadata for the docker image based on the GH Actions environment.
- name: Generate image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build ${{ matrix.platform }}
uses: docker/build-push-action@v6
id: build
with:
context: .
platforms: ${{ matrix.platform }}
tags: ${{ env.IMAGE }}
# push-by-digest means that the built image is not associated with a tag. Instead, the only way to refer to it
# is by using its digest (which is basically a unique hash).
outputs: type=image,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
# Export the digest outside of this job, so that the merge job can pick it up.
- name: Export digest
if: github.event_name != 'pull_request'
run: |
# Strip forward slash from matrix.platform
platform=${{ matrix.platform }}
echo "ARTIFACT_NAME=${platform//\//-}" >> $GITHUB_ENV
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
with:
name: digests-${{ env.ARTIFACT_NAME }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
# Build image for local use. Since we pushed by digest it has not been loaded into the local docker instance.
# It might be possible to directly push by using a unique tag and make this step redundant, but pushing by digest
# seems to be the recommended way to do it.
- name: Setup E2E test image
if: matrix.platform == 'linux/amd64'
uses: docker/build-push-action@v6
with:
# The cache should already provide this. So no rebuild should occur.
context: .
load: true
push: false
tags: ${{ env.IMAGE }}:tmp-${{ github.sha }}
- name: E2E in Docker
if: matrix.platform == 'linux/amd64'
run: |
sudo mkdir ${{ github.workspace }}/e2e_data
sudo chmod a+rwx ${{ github.workspace }}/e2e_data
sudo docker run -i --rm -v "${{ github.workspace }}/e2e_data:/app/e2e_data/" --entrypoint e2e/e2e.sh ${{ env.IMAGE }}:tmp-${{ github.sha }}
docker-merge:
if: github.event_name != 'pull_request'
needs: [ build ]
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate image metadata
id: meta
uses: docker/metadata-action@v5
env:
# We build multiplatform images which have an image index above the
# image manifests. Attach the annotations directly to the image index.
DOCKER_METADATA_ANNOTATIONS_LEVELS: "index"
with:
images: ${{ env.IMAGE }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Get short sha
id: sha
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Get PR number
id: pr
run: echo "pr_num=$(git log --format=%s -n 1 | sed -nr 's/.*\(\#([0-9]+)\)/\1/p')" >> $GITHUB_OUTPUT
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Merge amd64 + arm64 images into multi-arch manifest
# Changing the working directory to this folder is important, so that
# the '*' in printf down below is expanded to the simple filenames without
# a leading path in the way.
working-directory: ${{ runner.temp }}/digests
# steps.meta.outputs.annotations contains a line for every annotation.
# To properly handle the expansion of this multi-line value in bash,
# we need to properly transform it into the `EXPANDED_ANNOTATIONS`
# variable, which then no longer contains newlines and properly
# handles other spaces in the annotations.
run: |
ANNOTATIONS=$(cat <<'EOF'
${{ steps.meta.outputs.annotations }}
EOF
)
EXPANDED_ANNOTATIONS=()
while IFS= read -r line; do
# Skip empty lines
[[ -n "$line" ]] || continue
EXPANDED_ANNOTATIONS+=( --annotation "$line" )
done <<< "$ANNOTATIONS"
docker buildx imagetools create \
-t ${{ env.IMAGE }}:latest \
-t ${{ env.IMAGE }}:${{ github.ref_name == 'master' && format('pr-{0}', steps.pr.outputs.pr_num) || github.ref_name }} \
-t ${{ env.IMAGE }}:commit-${{ steps.sha.outputs.sha_short }} \
"${EXPANDED_ANNOTATIONS[@]}" \
$(printf '${{ env.IMAGE }}@sha256:%s ' *)