name: Build and publish image

# Publishes the multi-arch image (amd64 + arm64) to GitHub Packages
# (ghcr.io/dkam/clinch) whenever config/initializers/version.rb changes on
# main — a version bump IS the release. Each arch builds natively (no QEMU); a
# merge job stitches them into one manifest tagged :vX.Y.Z (+ :latest for
# non-pre-releases).
#
# To cut a release: edit Clinch::VERSION in config/initializers/version.rb,
# commit, push. For a dev build: set a pre-release version (e.g. "1.1.0-dev") —
# it publishes :v1.1.0-dev but does not move :latest. Or run this workflow
# manually from the Actions tab.

on:
  push:
    branches: [ main ]
    paths:
      - config/initializers/version.rb
  workflow_dispatch:

env:
  IMAGE: ghcr.io/${{ github.repository }}

jobs:
  # Read the SemVer constant; decide whether this release moves :latest.
  prepare:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
      latest: ${{ steps.version.outputs.latest }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Read version from config/initializers/version.rb
        id: version
        run: |
          V=$(ruby -e "require './config/initializers/version'; puts Clinch::VERSION")
          echo "version=$V" >> "$GITHUB_OUTPUT"
          # A pre-release (e.g. 1.1.0-dev) publishes its own tag but not :latest.
          if [[ "$V" == *-* ]]; then latest=false; else latest=true; fi
          echo "latest=$latest" >> "$GITHUB_OUTPUT"
          echo "Building v$V (move :latest = $latest)"

  build:
    needs: prepare
    runs-on: ${{ matrix.runner }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - platform: linux/amd64
            arch: amd64
            runner: ubuntu-latest
          - platform: linux/arm64
            arch: arm64
            runner: ubuntu-24.04-arm
    permissions:
      contents: read
      packages: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push by digest
        id: build
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: ${{ matrix.platform }}
          cache-from: type=gha,scope=${{ matrix.arch }}
          cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
          outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true

      - name: Export digest
        run: |
          mkdir -p /tmp/digests
          digest="${{ steps.build.outputs.digest }}"
          touch "/tmp/digests/${digest#sha256:}"

      - name: Upload digest
        uses: actions/upload-artifact@v4
        with:
          name: digests-${{ matrix.arch }}
          path: /tmp/digests/*
          if-no-files-found: error
          retention-days: 1

  merge:
    needs: [prepare, build]
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - name: Download digests
        uses: actions/download-artifact@v4
        with:
          path: /tmp/digests
          pattern: digests-*
          merge-multiple: true

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Create and push the multi-arch manifest
        working-directory: /tmp/digests
        run: |
          tags="-t ${{ env.IMAGE }}:v${{ needs.prepare.outputs.version }}"
          if [ "${{ needs.prepare.outputs.latest }}" = "true" ]; then
            tags="$tags -t ${{ env.IMAGE }}:latest"
          fi
          docker buildx imagetools create $tags $(printf '${{ env.IMAGE }}@sha256:%s ' *)

      - name: Inspect result
        run: docker buildx imagetools inspect ${{ env.IMAGE }}:latest
