name: release

# Triggered by tag pushes matching v*. Builds release binaries +
# Docker image, attaches them to the auto-generated GitHub Release.
#
# For pre-1.0 we keep this conservative: one platform (x86_64 Linux
# glibc) and one Docker image. Multi-arch and platform expansion can
# come later when we have downstream users asking.
#
# Note on downstream workflow chaining
# ------------------------------------
# `publish-pypi.yml` should fire after every `v*` tag. There are two
# paths into it, and we use both belt-and-suspenders style:
#
#   1. `on: release: published` — fires automatically *only* if the
#      release was created with a PAT (GitHub's loop-prevention rule
#      blocks downstream firing when the release is created with the
#      default GITHUB_TOKEN). Set `RELEASE_PAT` repo secret to enable.
#
#   2. The `trigger-publish-pypi` job at the bottom of this file — an
#      explicit `gh workflow run publish-pypi.yml --ref <tag>` after
#      `binaries` completes. `workflow_dispatch` is the documented
#      exception to the no-downstream rule, so this works with the
#      default GITHUB_TOKEN, no PAT required.
#
# v0.3.1 → v0.3.3 all required manual workflow_dispatch because path
# #1 was silently dropped (no PAT) and path #2 didn't exist yet.
on:
  push:
    tags:
      - 'v*'

permissions:
  contents: write   # create the Release + upload assets
  packages: write   # push to ghcr.io
  actions: write    # dispatch the publish-pypi workflow at the end

jobs:
  binaries:
    name: build binaries (x86_64-linux)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      - name: cargo build --release --workspace
        run: cargo build --release --workspace

      - name: Stage release artifacts
        run: |
          mkdir -p dist
          cp target/release/forkd            dist/
          cp target/release/forkd-controller dist/
          cd dist
          tar czf "../forkd-${GITHUB_REF_NAME}-x86_64-linux.tar.gz" \
              forkd forkd-controller
          cd ..
          sha256sum forkd-*.tar.gz > SHA256SUMS

      - name: Create / update GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          # Prefer the PAT so the `release: published` event fires
          # downstream workflows (publish-pypi.yml). Fall back to
          # GITHUB_TOKEN if the PAT secret isn't configured — the
          # release still lands, just without the auto-chain.
          token: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }}
          files: |
            forkd-*.tar.gz
            SHA256SUMS
          generate_release_notes: true
          # Don't auto-mark as a "latest release" for pre-1.0 unless
          # we explicitly want it; tag itself is enough.
          prerelease: false

  docker:
    name: build + push Docker image
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - 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 + push controller image
        uses: docker/build-push-action@v6
        with:
          context: .
          file: Dockerfile
          push: true
          tags: |
            ghcr.io/${{ github.repository_owner }}/forkd-controller:${{ github.ref_name }}
            ghcr.io/${{ github.repository_owner }}/forkd-controller:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

  # ---------------------------------------------------------------------
  # Chain to publish-pypi.yml.
  #
  # `on: release: published` doesn't auto-fire downstream workflows when
  # the release is created with the default GITHUB_TOKEN — GitHub's
  # infinite-loop guard. PAT works (see the file header) but requires
  # operator setup. workflow_dispatch is documented as the exception
  # (https://docs.github.com/en/actions/security-for-github-actions/
  # security-guides/automatic-token-authentication), so explicit
  # dispatch here covers both the "PAT not configured" case and the
  # "PAT misconfigured" case without any operator action.
  # ---------------------------------------------------------------------
  trigger-publish-pypi:
    name: trigger publish-pypi
    runs-on: ubuntu-latest
    needs: [binaries]
    # forkd-mcp uses its own tag prefix (mcp-v*); only chain the forkd
    # Python SDK publish for `v*` tags on the main package.
    if: startsWith(github.ref_name, 'v')
    steps:
      - uses: actions/checkout@v4
      - name: Dispatch publish-pypi.yml
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh workflow run publish-pypi.yml --ref "${GITHUB_REF_NAME}"
          echo "::notice::Dispatched publish-pypi.yml for ${GITHUB_REF_NAME}"
