name: CI

on:
  push:
    branches: [main]
    paths-ignore: ['**.md', 'docs/**', 'LICENSE']
  pull_request:
    branches: [main]
    paths-ignore: ['**.md', 'docs/**', 'LICENSE']
  workflow_call:

# Concurrency convention: see CONTRIBUTING.md → "GitHub Actions — Concurrency Convention".
# Hardcoded `CI-` prefix (not `${{ github.workflow }}`) because this workflow is
# invoked as a reusable workflow from publish.yml and release-candidate.yml. In
# called-workflow context `github.workflow` evaluation is ambiguous across GitHub
# Actions versions, and a prefix that could resolve to the caller's name would
# share a concurrency group with the caller → deadlock. A literal prefix is
# immune. Direct `push`/`pull_request` invocations use `CI-<ref>`; invocations
# from a reusable-workflow caller fall into a per-run-unique group that never
# serializes with the caller.
# cancel-in-progress is event-aware: cancel superseded PR runs, queue every other
# event (push to main, workflow_call from publish.yml, etc.).
concurrency:
  group: ${{ (github.event_name == 'pull_request' || github.event_name == 'push') && format('CI-{0}', github.ref) || format('CI-nested-{0}', github.run_id) }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

# ── Reusable workflow orchestration ─────────────────────────────────
# Each concern lives in its own workflow file for maintainability:
#   ci-quality.yml       — typecheck (tsc --noEmit)
#   ci-tests.yml         — unit + integration tests with coverage + cross-platform
#   ci-e2e.yml           — E2E tests (only when gitnexus-web/ changes)
#
# Shared setup is DRY via .github/actions/setup-gitnexus composite action.

jobs:
  quality:
    uses: ./.github/workflows/ci-quality.yml
    permissions:
      contents: read

  tests:
    uses: ./.github/workflows/ci-tests.yml
    permissions:
      contents: read

  e2e:
    uses: ./.github/workflows/ci-e2e.yml
    permissions:
      contents: read

  global-upgrade:
    uses: ./.github/workflows/ci-global-upgrade.yml
    permissions:
      contents: read

  # ── Save PR metadata for the reporting workflow ─────────────────
  # The ci-report.yml workflow (triggered by workflow_run) needs the
  # PR number and job results to post a comment.  We save them as an
  # artifact because workflow_run context doesn't reliably carry PR
  # info for fork PRs.
  save-pr-meta:
    name: Save PR Metadata
    if: always() && github.event_name == 'pull_request'
    needs: [quality, tests, e2e, global-upgrade]
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Write metadata
        shell: bash
        env:
          PR_NUMBER: ${{ github.event.number }}
          QUALITY: ${{ needs.quality.result }}
          TESTS: ${{ needs.tests.result }}
          E2E: ${{ needs.e2e.result }}
          GLOBAL_UPGRADE: ${{ needs.global-upgrade.result }}
        run: |
          mkdir -p pr-meta
          echo "$PR_NUMBER"  > pr-meta/pr_number
          echo "$QUALITY"    > pr-meta/quality_result
          echo "$TESTS"      > pr-meta/tests_result
          echo "$E2E"        > pr-meta/e2e_result
          # TODO(post-merge): remove backward-compat copies once ci-report.yml
          # on main reads underscore names.
          # Backward-compat: ci-report.yml on main still reads hyphenated
          # names.  workflow_run always executes from the default branch, so
          # the main-branch reader won't find the underscore variants until
          # this PR is merged.  Write both until then.
          cp pr-meta/pr_number       pr-meta/pr-number
          cp pr-meta/quality_result  pr-meta/quality-result
          cp pr-meta/tests_result    pr-meta/tests-result
          cp pr-meta/e2e_result      pr-meta/e2e-result

      - name: Upload PR metadata
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: pr-meta
          path: pr-meta/
          retention-days: 1

  # ── Unified CI gate ──────────────────────────────────────────────
  # Single required check for branch protection.
  ci-status:
    name: CI Gate
    needs: [quality, tests, e2e, global-upgrade]
    if: always()
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Check all jobs passed
        shell: bash
        env:
          QUALITY: ${{ needs.quality.result }}
          TESTS: ${{ needs.tests.result }}
          E2E: ${{ needs.e2e.result }}
          GLOBAL_UPGRADE: ${{ needs.global-upgrade.result }}
        run: |
          echo "Quality:        $QUALITY"
          echo "Tests:          $TESTS"
          echo "E2E:            $E2E"
          echo "Global upgrade: $GLOBAL_UPGRADE"
          if [[ "$QUALITY" != "success" ]] ||
             [[ "$TESTS" != "success" ]]; then
            echo "::error::Quality or test jobs failed"
            exit 1
          fi
          if [[ "$E2E" != "success" && "$E2E" != "skipped" ]]; then
            echo "::error::E2E job failed"
            exit 1
          fi
          if [[ "$GLOBAL_UPGRADE" != "success" && "$GLOBAL_UPGRADE" != "skipped" ]]; then
            echo "::error::Global upgrade smoke failed"
            exit 1
          fi
