name: Docker image build (Server) on: workflow_dispatch: inputs: version: description: "Image version/tag to publish, for example v1.0.0-beta" required: false type: string push: tags: ["v*"] permissions: contents: read packages: write attestations: write id-token: write jobs: build: name: Build (${{ matrix.arch }}) strategy: fail-fast: false matrix: include: - arch: amd64 platform: linux/amd64 runner: ubuntu-24.04 - arch: arm64 platform: linux/arm64 runner: ubuntu-24.04-arm runs-on: ${{ matrix.runner }} steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-tags: true fetch-depth: 0 persist-credentials: false - name: Set image metadata shell: bash env: INPUT_VERSION: ${{ github.event.inputs.version }} run: | POINTED_TAG="$(git tag --points-at HEAD --list 'v*' | sort -V | tail -n1)" INPUT_VERSION="${INPUT_VERSION//[[:space:]]/}" echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" if [[ "${GITHUB_REF}" == refs/tags/* ]]; then VERSION="${GITHUB_REF_NAME}" elif [[ -n "$INPUT_VERSION" ]]; then VERSION="$INPUT_VERSION" elif [[ -n "$POINTED_TAG" ]]; then VERSION="$POINTED_TAG" else echo "workflow_dispatch requires an explicit version input when HEAD is not tagged" >&2 exit 1 fi echo "VERSION=$VERSION" >> "$GITHUB_ENV" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Log into registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push id: build uses: docker/build-push-action@v7 with: context: . file: ./docker/Dockerfile platforms: ${{ matrix.platform }} outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true build-args: | VERSION=${{ env.VERSION }} cache-from: type=gha,scope=docker-server-${{ matrix.arch }} cache-to: type=gha,mode=max,ignore-error=true,timeout=20m,scope=docker-server-${{ matrix.arch }} - name: Export digest shell: bash run: | mkdir -p /tmp/server-digests touch "/tmp/server-digests/${DIGEST#sha256:}" env: DIGEST: ${{ steps.build.outputs.digest }} - name: Upload digest uses: actions/upload-artifact@v4 with: name: server-digests-${{ matrix.arch }} path: /tmp/server-digests/* if-no-files-found: error retention-days: 1 - name: Generate artifact attestation uses: actions/attest-build-provenance@v3 with: subject-name: ${{ env.IMAGE }} subject-digest: ${{ steps.build.outputs.digest }} push-to-registry: true merge: name: Merge multi-arch manifest runs-on: ubuntu-24.04 needs: build steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-tags: true fetch-depth: 0 persist-credentials: false - name: Set image metadata shell: bash env: INPUT_VERSION: ${{ github.event.inputs.version }} run: | POINTED_TAG="$(git tag --points-at HEAD --list 'v*' | sort -V | tail -n1)" INPUT_VERSION="${INPUT_VERSION//[[:space:]]/}" echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" if [[ "${GITHUB_REF}" == refs/tags/* ]]; then VERSION="${GITHUB_REF_NAME}" elif [[ -n "$INPUT_VERSION" ]]; then VERSION="$INPUT_VERSION" elif [[ -n "$POINTED_TAG" ]]; then VERSION="$POINTED_TAG" else echo "workflow_dispatch requires an explicit version input when HEAD is not tagged" >&2 exit 1 fi echo "VERSION=$VERSION" >> "$GITHUB_ENV" - name: Download digests uses: actions/download-artifact@v4 with: path: /tmp/server-digests pattern: server-digests-* merge-multiple: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Log into registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Create and push manifest list working-directory: /tmp/server-digests shell: bash run: | shopt -s nullglob references=() for digest in *; do references+=("${IMAGE}@sha256:${digest}") done if [ ${#references[@]} -eq 0 ]; then echo "No digests found in /tmp/server-digests" >&2 exit 1 fi if [[ "${VERSION}" =~ (alpha|beta|rc) ]]; then FLOATING_TAG="beta" else FLOATING_TAG="latest" fi docker buildx imagetools create \ -t "${IMAGE}:${VERSION}" \ -t "${IMAGE}:${FLOATING_TAG}" \ "${references[@]}" - name: Inspect image run: docker buildx imagetools inspect "${IMAGE}:${VERSION}"