name: Build Docker permissions: contents: read # needed to checkout repo packages: write # needed for interacting with GHCR on: push: branches: - master pull_request: branches: - master paths: - '.github/workflows/docker-release.yml' - '.dockerignore' - 'Dockerfile' - 'docker-compose.yml' - 'docker-compose.yml.windows' release: types: - released # publishing of stable releases # Cancel earlier, unfinished runs of this workflow on the same branch (unless on release) concurrency: group: "${{ github.workflow }} @ ${{ github.ref_name }}" cancel-in-progress: ${{ github.event_name != 'release' }} env: GHCR_IMAGE: ghcr.io/cockatrice/servatrice OCI_DESCRIPTION: Server for Cockatrice, a cross-platform virtual tabletop for multiplayer card games OCI_TITLE: Servatrice OCI_URL: https://cockatrice.github.io/ jobs: # Create one platform-specific image and publish its OCI image manifest per matrix job build: name: "Servatrice (${{ matrix.label }})" if: github.repository_owner == 'Cockatrice' runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: include: - label: x86 platform: linux/amd64 runner: ubuntu-latest # https://github.com/actions/runner-images - label: arm platform: linux/arm64 runner: ubuntu-24.04-arm # https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Arm64-Readme.md, replace with "ubuntu-latest-arm" once available env: CACHE_SCOPE: servatrice-${{ matrix.label }} steps: - name: "Checkout" uses: actions/checkout@v7 - name: "Set up Docker buildx" uses: docker/setup-buildx-action@v4 - name: "Login to GitHub Container Registry (GHCR)" if: github.event_name == 'release' && github.event.release.prerelease == false id: login uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ github.token }} # Don't push for non-release triggers - name: "Build image" if: steps.login.outcome != 'success' uses: docker/build-push-action@v7 with: cache-from: type=gha,scope=${{ env.CACHE_SCOPE }} cache-to: ${{ case(github.ref == 'refs/heads/master', format('type=gha,mode=max,scope={0}', env.CACHE_SCOPE), '') }} context: . platforms: ${{ matrix.platform }} push: false # Add OCI labels and push single-platform image by digest (without tags) - name: "Build image and push by digest" if: steps.login.outcome == 'success' id: build uses: docker/build-push-action@v7 with: cache-from: type=gha,scope=${{ env.CACHE_SCOPE }} cache-to: type=gha,mode=max,scope=${{ env.CACHE_SCOPE }} context: . labels: | org.opencontainers.image.description=${{ env.OCI_DESCRIPTION }} org.opencontainers.image.title=${{ env.OCI_TITLE }} org.opencontainers.image.url=${{ env.OCI_URL }} outputs: type=image,name=${{ env.GHCR_IMAGE }},name-canonical=true,push=true,push-by-digest=true platforms: ${{ matrix.platform }} provenance: mode=max # Do not pass secrets as build arguments with this option sbom: true - name: "Export digest" if: steps.login.outcome == 'success' env: DIGEST: ${{ steps.build.outputs.digest }} run: | mkdir -p "$RUNNER_TEMP/digests" touch "$RUNNER_TEMP/digests/${DIGEST#sha256:}" - name: "Upload digest" if: steps.login.outcome == 'success' uses: actions/upload-artifact@v7 with: archive: false if-no-files-found: error name: digest-${{ matrix.label }} path: ${{ runner.temp }}/digests/* retention-days: 1 # Create an OCI image index from the platform-specific image manifests index: name: "Publish multi-platform Servatrice image" if: github.repository_owner == 'Cockatrice' && github.event_name == 'release' && github.event.release.prerelease == false needs: build runs-on: ubuntu-slim # https://github.com/actions/runner-images/blob/main/images/ubuntu-slim/ubuntu-slim-Readme.md steps: - name: "Download digests" uses: actions/download-artifact@v7 with: path: ${{ runner.temp }}/digests pattern: digest-* merge-multiple: true - name: "Login to GitHub Container Registry (GHCR)" uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ github.token }} - name: "Docker metadata" id: metadata uses: docker/metadata-action@v6 with: images: ${{ env.GHCR_IMAGE }} flavor: | latest=auto tags: | type=ref,event=tag # if semver, also: type=semver,pattern={{version}} / {{major}}.{{minor}} # Add OCI annotations to image index and publish tags - name: "Create image index" env: DOCKER_TAGS: ${{ steps.metadata.outputs.tags }} working-directory: ${{ runner.temp }}/digests run: | TAG_ARGS=() while IFS= read -r tag; do TAG_ARGS+=(--tag "$tag") done <<< "$DOCKER_TAGS" DIGEST_ARGS=() for digest in *; do DIGEST_ARGS+=("$GHCR_IMAGE@sha256:$digest") done docker buildx imagetools create \ --prefer-index=true \ --annotation "index:org.opencontainers.image.description=$OCI_DESCRIPTION" \ --annotation "index:org.opencontainers.image.title=$OCI_TITLE" \ --annotation "index:org.opencontainers.image.url=$OCI_URL" \ "${TAG_ARGS[@]}" \ "${DIGEST_ARGS[@]}" - name: "Inspect images" env: GITHUB_TAG: ${{ github.ref_name }} run: | docker buildx imagetools inspect "$GHCR_IMAGE:latest" docker buildx imagetools inspect "$GHCR_IMAGE:$GITHUB_TAG"