This repository was archived by the owner on Apr 4, 2026. It is now read-only.
refactor: data-driven multi-arch build system with ARM64 support #5
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 PostGIS CI | |
| on: | |
| push: | |
| branches: [v2-multi-arch, master] | |
| pull_request: | |
| schedule: | |
| - cron: '15 5 * * 1' | |
| workflow_dispatch: | |
| defaults: | |
| run: | |
| shell: bash | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Job 1: Generate build matrix from versions.json | |
| # --------------------------------------------------------------------------- | |
| generate-matrix: | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| build-matrix: ${{ steps.matrix.outputs.build }} | |
| manifest-matrix: ${{ steps.matrix.outputs.manifest }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Generate matrices from versions.json | |
| id: matrix | |
| run: | | |
| # Build matrix: one entry per (version, variant, arch) | |
| BUILD=$(jq -c '[ | |
| to_entries[] | .key as $ver | .value | | |
| to_entries[] | .key as $var | .value | | |
| (.arch | split(" "))[] as $arch | | |
| { | |
| version: $ver, | |
| variant: $var, | |
| arch: $arch, | |
| tags: .tags, | |
| template: .template, | |
| is_master: ($ver | endswith("-master")) | |
| } | |
| ]' versions.json) | |
| # Manifest matrix: one entry per (version, variant) that has multiple arches | |
| MANIFEST=$(jq -c '[ | |
| to_entries[] | .key as $ver | .value | | |
| to_entries[] | .key as $var | .value | | |
| select((.arch | split(" ") | length) > 1) | | |
| { | |
| version: $ver, | |
| variant: $var, | |
| tags: .tags | |
| } | |
| ] | unique_by(.version + "-" + .variant)' versions.json) | |
| echo "build={\"include\":$BUILD}" >> "$GITHUB_OUTPUT" | |
| echo "manifest={\"include\":$MANIFEST}" >> "$GITHUB_OUTPUT" | |
| echo "Build matrix entries: $(echo "$BUILD" | jq length)" | |
| echo "Manifest entries: $(echo "$MANIFEST" | jq length)" | |
| # --------------------------------------------------------------------------- | |
| # Job 2: Build and push per-architecture images | |
| # --------------------------------------------------------------------------- | |
| build: | |
| needs: generate-matrix | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.generate-matrix.outputs.build-matrix) }} | |
| name: ${{ matrix.version }}/${{ matrix.variant }} (${{ matrix.arch }}) | |
| runs-on: ${{ matrix.arch == 'amd64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }} | |
| continue-on-error: ${{ matrix.is_master }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| if: github.event_name != 'pull_request' | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Compute image metadata | |
| id: meta | |
| run: | | |
| REPO="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | |
| REPO=$(echo "$REPO" | tr '[:upper:]' '[:lower:]') | |
| echo "repo=${REPO}" >> "$GITHUB_OUTPUT" | |
| - name: Build image | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ${{ matrix.version }}/${{ matrix.variant }} | |
| platforms: linux/${{ matrix.arch }} | |
| push: ${{ github.event_name != 'pull_request' }} | |
| outputs: ${{ github.event_name != 'pull_request' && format('type=image,name={0},push-by-digest=true,name-canonical=true', steps.meta.outputs.repo) || '' }} | |
| cache-from: type=gha,scope=${{ matrix.version }}-${{ matrix.variant }}-${{ matrix.arch }} | |
| cache-to: type=gha,mode=max,scope=${{ matrix.version }}-${{ matrix.variant }}-${{ matrix.arch }} | |
| - name: Export digest | |
| if: github.event_name != 'pull_request' | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| if: github.event_name != 'pull_request' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: digest-${{ matrix.version }}-${{ matrix.variant }}-${{ matrix.arch }} | |
| path: /tmp/digests/ | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # --------------------------------------------------------------------------- | |
| # Job 3: Create and push multi-arch manifests | |
| # --------------------------------------------------------------------------- | |
| manifest: | |
| if: github.event_name != 'pull_request' | |
| needs: [generate-matrix, build] | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.generate-matrix.outputs.manifest-matrix) }} | |
| name: manifest ${{ matrix.version }}/${{ matrix.variant }} | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download amd64 digest | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: digest-${{ matrix.version }}-${{ matrix.variant }}-amd64 | |
| path: /tmp/digests/ | |
| - name: Download arm64 digest | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: digest-${{ matrix.version }}-${{ matrix.variant }}-arm64 | |
| path: /tmp/digests/ | |
| - name: Create and push manifests | |
| run: | | |
| REPO="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | |
| REPO=$(echo "$REPO" | tr '[:upper:]' '[:lower:]') | |
| # Collect digests | |
| SOURCES="" | |
| for f in /tmp/digests/*; do | |
| SOURCES="${SOURCES} ${REPO}@sha256:$(basename $f)" | |
| done | |
| # Create a manifest for each tag | |
| IFS=' ' read -ra TAGS <<< "${{ matrix.tags }}" | |
| TAG_ARGS="" | |
| for tag in "${TAGS[@]}"; do | |
| TAG_ARGS="${TAG_ARGS} --tag ${REPO}:${tag}" | |
| done | |
| echo "Creating manifests for tags: ${TAGS[*]}" | |
| docker buildx imagetools create ${TAG_ARGS} ${SOURCES} | |
| - name: Inspect primary tag | |
| run: | | |
| REPO="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" | |
| REPO=$(echo "$REPO" | tr '[:upper:]' '[:lower:]') | |
| FIRST_TAG=$(echo "${{ matrix.tags }}" | cut -d' ' -f1) | |
| docker buildx imagetools inspect "${REPO}:${FIRST_TAG}" |