name: Build and Push donut-sync Docker Image

on:
  push:
    branches: [main]
    paths:
      - "donut-sync/**"
  workflow_call:
    inputs:
      tag:
        description: "Docker tag (e.g., v1.0.0)"
        required: true
        type: string
    secrets:
      DOCKERHUB_USERNAME:
        required: true
      DOCKERHUB_TOKEN:
        required: true
  workflow_dispatch:
    inputs:
      tag:
        description: "Docker tag (e.g., v1.0.0, latest)"
        required: true
        default: "latest"

permissions:
  contents: read

env:
  REGISTRY: docker.io
  IMAGE_NAME: donutbrowser/donut-sync

jobs:
  # donut-sync's own end-to-end suite covers which host it signs into presigned
  # URLs. That is the whole of the self-hosted sync failure in issue 534: sign
  # against an address only the server can reach and every client transfer dies
  # at connect while /health and /readyz stay green. The suite existed and was
  # never run by anything, so the guard was decorative. Run it here, before the
  # image ships, because an image with broken presigning is the thing that
  # reaches users.
  #
  # Ubuntu only, and separate from the Rust and Node matrices, because it needs
  # Docker for MinIO and a POSIX env-var prefix in the package script.
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7.0.1

      - name: Set up pnpm package manager
        uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 #v6.0.10
        with:
          run_install: false

      - name: Set up Node.js
        uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 #v7.0.0
        with:
          node-version-file: .node-version
          cache: "pnpm"

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      # Publishes MinIO on 8987, which is the port test/test-env.ts pins.
      - name: Start test storage
        run: docker compose -f donut-sync/docker-compose.yml up -d --wait

      - name: Run donut-sync end-to-end tests
        working-directory: ./donut-sync
        run: pnpm test:e2e

      - name: Stop test storage
        if: always()
        run: docker compose -f donut-sync/docker-compose.yml down -v

  build-and-push:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7.0.1

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e #v4.3.0

      - name: Log in to Docker Hub
        uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f #v4.6.0
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Determine tags
        id: tags
        env:
          INPUT_TAG: ${{ inputs.tag }}
          EVENT_NAME: ${{ github.event_name }}
          COMMIT_SHA: ${{ github.sha }}
        run: |
          TAGS=""

          if [ -n "$INPUT_TAG" ]; then
            # Called from release workflow or manual dispatch
            if [[ ! "$INPUT_TAG" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$ ]]; then
              echo "Invalid Docker tag" >&2
              exit 1
            fi
            TAGS="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${INPUT_TAG}"
            TAGS="${TAGS},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"
          elif [ "$EVENT_NAME" = "push" ]; then
            # Push to main (nightly): tag with nightly and commit SHA
            SHORT_SHA=${COMMIT_SHA:0:7}
            TAGS="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly"
            TAGS="${TAGS},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:nightly-${SHORT_SHA}"
          fi

          printf 'tags=%s\n' "$TAGS" >> "$GITHUB_OUTPUT"

      - name: Build and push Docker image
        uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a #v7.3.0
        with:
          context: .
          file: ./donut-sync/Dockerfile
          push: true
          tags: ${{ steps.tags.outputs.tags }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64,linux/arm64
