# M6-D6: the tag-triggered release pipeline (grill decision 9, ADR-0015).
#
# CI's half of the ceremony: build the platform binaries on both self-hosted
# runners, assemble the asset set the self-updater + installer consume
# (binaries, SHA256SUMS, manifest.schema.json, mock-adapter.zip), and create
# a DRAFT release on SaberMage/spt-releases (cross-repo via the
# RELEASES_TOKEN fine-grained PAT).
#
# The maintainer's half stays manual and local (no signing keys in CI):
#   1. download the draft's binaries (or use the local builds)
#   2. SPT_RELEASE_SEED=<seed> cargo run -p xtask -- release-sign \
#        --key-id rel-primary-2026 --version <N> spt-x86_64-* …
#   3. gh release upload <tag> *.release.json --repo SaberMage/spt-releases
#   4. publish the draft
#
# [impl->REQ-REL-2]
name: release

on:
  push:
    tags: ["v*"]

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          - runner: [self-hosted, Linux, kitsubito]
            asset: spt-x86_64-linux
            built: target/release/spt
          - runner: [self-hosted, Windows, hfenduleam]
            asset: spt-x86_64-windows.exe
            built: target/release/spt.exe
    runs-on: ${{ matrix.runner }}
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v5
      - name: Build release binary
        run: cargo build --release -p spt --bin spt
      # Two staging steps: the Windows runner has no bash on PATH (the same
      # fact the dormancy-budget steps already encode) — each OS keeps its
      # native shell.
      - name: Stage asset (linux)
        if: runner.os == 'Linux'
        run: |
          mkdir -p dist
          cp "${{ matrix.built }}" "dist/${{ matrix.asset }}"
      - name: Stage asset (windows)
        if: runner.os == 'Windows'
        # pwsh (PowerShell 7), not Windows PowerShell 5.1: the runner's 5.1
        # execution policy blocks GitHub's dot-sourced temp script
        # (PSSecurityException). pwsh is the runner's default shell (the build
        # step above runs under it) and carries its own, permissive policy.
        shell: pwsh
        run: |
          New-Item -ItemType Directory -Force dist | Out-Null
          Copy-Item "${{ matrix.built }}" "dist/${{ matrix.asset }}"
      - uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.asset }}
          path: dist/${{ matrix.asset }}
          if-no-files-found: error

  assemble:
    needs: build
    runs-on: [self-hosted, Linux, kitsubito]
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v5
      - uses: actions/download-artifact@v4
        with:
          path: dist
          merge-multiple: true
      - name: Assemble asset set
        # The exact set REQ-REL-2 names: platform binaries + SHA256SUMS (what
        # install.sh/.ps1 verify) + the manifest schema + the mock-adapter
        # source zip (the adapter quickstart's reference download).
        run: |
          cd dist
          sha256sum spt-x86_64-linux spt-x86_64-windows.exe > SHA256SUMS
          cp ../crates/spt-runtime/manifest.schema.json .
          # Zip rooted at the adapter dir so `unzip -d mock-adapter` yields
          # mock-adapter/manifest.toml exactly as the adapter quickstart says.
          (cd ../adapters/mock && zip -r "$OLDPWD/mock-adapter.zip" . \
             -x 'target/*')
          ls -la
      - name: Build user-facing release notes from CHANGELOG
        # The release BODY is the user-facing changelog: the `## [<version>]`
        # section of CHANGELOG.md (Added / Changed / Fixed, UX items only — no
        # internal lingo). Authoring that section before tagging is a required
        # release step (docs/RELEASE-RUNBOOK.md). A missing section fails the
        # release loudly rather than shipping an empty/boilerplate body — the
        # changelog is not optional.
        run: |
          ver="${GITHUB_REF_NAME#v}"   # v0.1.2 -> 0.1.2
          notes="dist/RELEASE_NOTES.md"
          # Literal string matching (index, not regex) so the section header is
          # matched identically across awk dialects — no bracket-escaping traps.
          awk -v want="## [${ver}]" '
            index($0, want) == 1 { grab=1; next }
            grab && index($0, "## [") == 1 { exit }
            grab { print }
          ' CHANGELOG.md > "$notes"
          if ! grep -q '[^[:space:]]' "$notes"; then
            echo "::error::CHANGELOG.md has no '## [$ver]' section — add the user-facing changelog for this release before tagging (see docs/RELEASE-RUNBOOK.md)."
            exit 1
          fi
          echo "----- release body for ${GITHUB_REF_NAME} -----"
          cat "$notes"
      - name: Create draft release on spt-releases
        env:
          GH_TOKEN: ${{ secrets.RELEASES_TOKEN }}
        run: |
          gh release create "${GITHUB_REF_NAME}" \
            --repo SaberMage/spt-releases \
            --draft \
            --title "spt ${GITHUB_REF_NAME}" \
            --notes-file dist/RELEASE_NOTES.md \
            dist/spt-x86_64-linux \
            dist/spt-x86_64-windows.exe \
            dist/SHA256SUMS \
            dist/manifest.schema.json \
            dist/mock-adapter.zip
