# Quality Gates Provenance — routes PRs to the release branch into the correct
# Quality Gates path.
#
# Generated by `devaudit install` / `devaudit update` from sdlc-config.json.
# Do not edit manually — re-run the CLI (`devaudit update`) to regenerate.
#
# Why this exists (devaudit-installer#280):
#   ci.yml and ci-status-fallback.yml only run on pushes/PRs to develop.
#   A PR to main can be opened for a head SHA that never received a develop-side
#   Quality Gates result. When that happens, neither existing workflow fires on
#   the PR to main, so the release PR sits with missing/ambiguous protection.
#
#   This workflow fires on PRs to {{RELEASE_BRANCH}} and chooses between two modes:
#   - release PR (`{{INTEGRATION_BRANCH}} -> {{RELEASE_BRANCH}}`): same-SHA provenance
#     check only
#   - hotfix PR (`hotfix/* -> {{RELEASE_BRANCH}}`): dispatch the real ci.yml gates on
#     the hotfix branch and proxy that result back onto the PR
#
#   The job name is exactly `Quality Gates` to satisfy existing branch-protection
#   rules without introducing a new required-check name.

name: CI Pipeline

on:
  workflow_dispatch:
  pull_request:
    branches: [{{RELEASE_BRANCH}}]

# A repo with tightened default GITHUB_TOKEN permissions (GitHub's
# increasingly common secure-by-default setting) grants only `contents:
# read` unless a workflow asks for more — this job's "Verify prior Quality
# Gates success" step reads check-runs (`checks: read`) and the hotfix path
# dispatches + watches a run (`actions: write`), so both must be requested
# explicitly or the same-SHA provenance check 403s outright on such a repo.
permissions:
  contents: read
  checks: read
  actions: write

jobs:
  release-scope-integrity:
    name: Release Scope Integrity
    if: ${{ !startsWith(github.event.pull_request.head.ref, 'hotfix/') && !startsWith(github.event.pull_request.head.ref, 'fix/hotfix-') }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 0

      - name: Check release PR metadata against derived scope
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}
          PR_BODY: ${{ github.event.pull_request.body }}
          HEAD_REF: ${{ github.event.pull_request.head.ref }}
          BASE_REF: ${{ github.event.pull_request.base.ref }}
          INTEGRATION_BRANCH: {{INTEGRATION_BRANCH}}
          RELEASE_BRANCH: {{RELEASE_BRANCH}}
        run: |
          chmod +x scripts/check-release-pr-scope.sh 2>/dev/null || true
          bash scripts/check-release-pr-scope.sh

  quality-gates:
    name: Quality Gates
    runs-on: ubuntu-latest
    steps:
      - name: Classify PR path
        id: classify
        env:
          HEAD_REF: ${{ github.event.pull_request.head.ref }}
          BASE_REF: ${{ github.event.pull_request.base.ref }}
        run: |
          case "$HEAD_REF" in
            hotfix/*|fix/hotfix-*)
              echo "kind=hotfix" >> "$GITHUB_OUTPUT"
              ;;
            *)
              echo "kind=release" >> "$GITHUB_OUTPUT"
              ;;
          esac
          echo "base_ref=${BASE_REF}" >> "$GITHUB_OUTPUT"
          echo "head_ref=${HEAD_REF}" >> "$GITHUB_OUTPUT"

      - name: Dispatch ci.yml Quality Gates for hotfix PR
        if: steps.classify.outputs.kind == 'hotfix'
        env:
          GH_TOKEN: ${{ github.token }}
          HEAD_REF: ${{ steps.classify.outputs.head_ref }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
        run: |
          BEFORE_JSON=$(gh run list \
            --workflow "CI Pipeline" \
            --branch "$HEAD_REF" \
            --event workflow_dispatch \
            --limit 50 \
            --json databaseId,headSha)

          gh workflow run ci.yml --ref "$HEAD_REF"

          RUN_ID=""
          for ATTEMPT in $(seq 1 20); do
            AFTER_JSON=$(gh run list \
              --workflow "CI Pipeline" \
              --branch "$HEAD_REF" \
              --event workflow_dispatch \
              --limit 50 \
              --json databaseId,headSha)
            RUN_ID=$(BEFORE_JSON="$BEFORE_JSON" AFTER_JSON="$AFTER_JSON" HEAD_SHA="$HEAD_SHA" python3 - <<'PY'
            import json
            import os

            before = {str(item["databaseId"]) for item in json.loads(os.environ["BEFORE_JSON"])}
            head_sha = os.environ["HEAD_SHA"]
            for item in json.loads(os.environ["AFTER_JSON"]):
                if item.get("headSha") == head_sha and str(item["databaseId"]) not in before:
                    print(item["databaseId"])
                    break
            PY
            )
            if [ -n "$RUN_ID" ]; then
              break
            fi
            echo "Waiting for dispatched ci.yml run to appear for ${HEAD_REF}..."
            sleep 10
          done

          if [ -z "$RUN_ID" ]; then
            echo "::error::Unable to locate the dispatched ci.yml run for hotfix branch ${HEAD_REF}."
            exit 1
          fi

          echo "Watching dispatched ci.yml run ${RUN_ID} for hotfix branch ${HEAD_REF}..."
          gh run watch "$RUN_ID" --exit-status

      - name: Verify prior Quality Gates success on head SHA
        if: steps.classify.outputs.kind != 'hotfix'
        env:
          GH_TOKEN: ${{ github.token }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
          CURRENT_RUN_ID: ${{ github.run_id }}
        run: |
          echo "Checking for prior successful 'Quality Gates' on SHA: $HEAD_SHA"
          echo "Excluding current workflow run: $CURRENT_RUN_ID"
          CURRENT_RUN_URL="/actions/runs/${CURRENT_RUN_ID}"
          MAX_ATTEMPTS=10
          WAIT_SECONDS=30

          for ATTEMPT in $(seq 1 $MAX_ATTEMPTS); do
            RESPONSE=$(gh api \
              "/repos/${{ github.repository }}/commits/${HEAD_SHA}/check-runs?name=Quality%20Gates" \
              --jq ".check_runs[]
                | select(.status == \"completed\" and .conclusion == \"success\")
                | select((.details_url // \"\") | contains(\"${CURRENT_RUN_URL}\") | not)")

            if [ -n "$RESPONSE" ]; then
              echo "Found prior successful Quality Gates result:"
              echo "$RESPONSE" | head -5
              echo ""
              echo "Provenance verified — this SHA passed develop-side Quality Gates."
              exit 0
            fi

            if [ "$ATTEMPT" -lt "$MAX_ATTEMPTS" ]; then
              echo "Develop-side Quality Gates for SHA ${HEAD_SHA} not successful yet. Waiting ${WAIT_SECONDS}s (${ATTEMPT}/${MAX_ATTEMPTS})..."
              sleep "$WAIT_SECONDS"
            fi
          done

          echo "::error::No successful develop-side Quality Gates result found for SHA ${HEAD_SHA} after waiting $((MAX_ATTEMPTS * WAIT_SECONDS / 60)) minutes."
          echo "::error::Push this exact commit through the normal develop flow first, or wait for the in-flight develop pipeline to finish and rerun this check."
          exit 1
