ci(docker): pin the cross-compile multi-arch image build to the wg1 s… #50
This file contains hidden or 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
| name: docker | |
| # Build (and, except on pull requests, publish) the multi-architecture Graphus container image — | |
| # linux/amd64 + linux/arm64 — to the GitHub Container Registry. | |
| # | |
| # CROSS-COMPILED on a native x86_64 self-hosted runner: the Dockerfile builder is pinned to | |
| # `--platform=$BUILDPLATFORM`, so the heavy Rust compile always runs natively on the x86 runner and | |
| # cross-compiles the arm64 (Raspberry Pi 5 / Apple Silicon) binary — no emulated compile on the slow | |
| # Pi. QEMU is set up only for the tiny arm64 runtime layers (a handful of `apt-get`s). One `buildx` | |
| # invocation yields the full multi-arch manifest. | |
| # | |
| # * Pull requests → amd64-only build (no push) on a GitHub-hosted runner (public-repo security: | |
| # never run fork-PR code on a self-hosted machine). | |
| # * Pushes to main → build + push the `:main` multi-arch manifest (dev image; the release image is | |
| # handled by dockerhub.yml). | |
| # * Tags `v*` / dispatch → build + push a full `:vX.Y.Z` / `:X.Y` / `:latest` manifest. | |
| # | |
| # NOTE: this workflow only BUILDS the image (the Dockerfile compiles the binary); it never runs the | |
| # cargo test suite. The tests live in ci.yml and run on pull requests / manual dispatch only. | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| pull_request: | |
| paths: | |
| - "Dockerfile" | |
| - ".dockerignore" | |
| - "docker/**" | |
| - "docker-compose.yml" | |
| - ".github/workflows/docker.yml" | |
| - "crates/**" | |
| - "Cargo.toml" | |
| - "Cargo.lock" | |
| workflow_dispatch: | |
| concurrency: | |
| group: docker-${{ github.ref }} | |
| # Only cancel superseded pull-request builds (they never push). A run on main, a tag, or a dispatch | |
| # publishes a multi-arch manifest, and a half-pushed manifest is worse than waiting. | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| IMAGE_NAME: ghcr.io/${{ github.repository }} | |
| PLATFORMS: linux/amd64,linux/arm64 | |
| jobs: | |
| build: | |
| # Cross-compile on a native x86_64 self-hosted runner for trusted events; PRs stay on a | |
| # GitHub-hosted runner so untrusted fork code never runs on the self-hosted machines. | |
| runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-latest' || fromJSON('["self-hosted", "Linux", "X64", "wg1"]') }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| # QEMU is needed only for the arm64 RUNTIME layers (the runtime stage's `apt-get`); the Rust | |
| # compile is cross-compiled natively on x86 by the `--platform=$BUILDPLATFORM` builder stage. | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| # Only publish for pushes/tags/dispatch; PRs build without pushing. | |
| - name: Decide whether to push | |
| id: gate | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| echo "push=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "push=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Log in to GHCR | |
| if: steps.gate.outputs.push == 'true' | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # metadata-action lowercases the image reference automatically (github.repository preserves the | |
| # owner's case), so the derived tags are always registry-valid. | |
| - name: Derive image tags and labels | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=pr | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} | |
| - name: Build and push (multi-arch, cross-compiled) | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| # PRs build the native amd64 image only (fast); pushes/tags cross-compile the full multi-arch | |
| # manifest so arm64 is validated before it can ship. | |
| platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || env.PLATFORMS }} | |
| push: ${{ steps.gate.outputs.push }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| provenance: true | |
| sbom: true | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max |