name: CI

on:
  pull_request:
    branches: [main]
  push:
    branches:
      - main
      - "awp/**"

concurrency:
  group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

permissions:
  contents: read
  packages: read
  issues: write

jobs:
  ci:
    name: CI
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # Docs-only fast path: if every changed file is *.md, docs/**, or *.html,
      # skip the gate steps below and let this job report success quickly.
      # This job (not individual steps) is what should be set as the required
      # status check, since a skipped step still leaves the job green.
      - name: Determine changed paths
        id: diff
        env:
          EVENT_NAME: ${{ github.event_name }}
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
          BEFORE_SHA: ${{ github.event.before }}
          AFTER_SHA: ${{ github.sha }}
        run: |
          set -euo pipefail

          if [ "$EVENT_NAME" = "pull_request" ]; then
            RANGE="$BASE_SHA...$HEAD_SHA"
          elif [ -z "$BEFORE_SHA" ] || [ "$BEFORE_SHA" = "0000000000000000000000000000000000000000" ]; then
            # New branch / first push: can't diff against a real "before", so
            # don't risk a false docs-only skip.
            echo "docs_only=false" >> "$GITHUB_OUTPUT"
            exit 0
          else
            RANGE="$BEFORE_SHA...$AFTER_SHA"
          fi

          CHANGED_FILES=$(git diff --name-only "$RANGE" || true)

          if [ -z "$CHANGED_FILES" ]; then
            echo "docs_only=false" >> "$GITHUB_OUTPUT"
            exit 0
          fi

          echo "Changed files:"
          echo "$CHANGED_FILES"

          NON_DOCS=$(echo "$CHANGED_FILES" | grep -Ev '(^|/)docs/|\.md$|\.html$' || true)

          if [ -z "$NON_DOCS" ]; then
            echo "docs_only=true" >> "$GITHUB_OUTPUT"
          else
            echo "docs_only=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Docs-only fast path
        if: steps.diff.outputs.docs_only == 'true'
        run: echo "Docs-only change (*.md, docs/**, *.html) — skipping build/test gates."

      - name: Setup pnpm
        if: steps.diff.outputs.docs_only != 'true'
        uses: pnpm/action-setup@v4
        with:
          version: 9.7.0

      - name: Setup Node.js
        if: steps.diff.outputs.docs_only != 'true'
        uses: actions/setup-node@v4
        with:
          node-version: "22"
          cache: pnpm
          registry-url: "https://npm.pkg.github.com"
          scope: "@platform-modules"

      - name: Install dependencies
        if: steps.diff.outputs.docs_only != 'true'
        run: pnpm install --frozen-lockfile
        env:
          # @platform-modules/db is a private GitHub Packages dependency.
          # Requires a repo secret with `read:packages` on the platform-modules
          # org — see workflow notes / CI report for setup.
          NODE_AUTH_TOKEN: ${{ secrets.PLATFORM_MODULES_NPM_TOKEN || secrets.GITHUB_TOKEN }}

      - name: Typecheck
        if: steps.diff.outputs.docs_only != 'true'
        run: pnpm typecheck

      - name: Lint
        if: steps.diff.outputs.docs_only != 'true'
        run: pnpm lint

      - name: Test
        if: steps.diff.outputs.docs_only != 'true'
        run: pnpm test

      - name: Build
        if: steps.diff.outputs.docs_only != 'true'
        run: pnpm build

      - name: Architecture tests
        if: steps.diff.outputs.docs_only != 'true'
        run: pnpm test:architecture

      - name: Format check
        if: steps.diff.outputs.docs_only != 'true'
        run: pnpm format:check

      # Internal merge protection (governance amendment A7): GitHub branch
      # protection is unavailable on this plan, so a red main must raise a
      # loud, durable alarm instead of relying on anyone watching the Actions
      # tab. Red main = stop-the-line until green (fix forward or revert).
      - name: Stop-the-line alarm on red main
        if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          set -euo pipefail
          SHORT_SHA="${GITHUB_SHA:0:7}"
          RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
          EXISTING=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open --search "STOP-THE-LINE in:title" --json number --jq 'length')
          if [ "$EXISTING" -gt 0 ]; then
            echo "Open STOP-THE-LINE issue already exists; not duplicating."
            exit 0
          fi
          BODY=$(printf 'CI failed on a push to main: %s\n\nPer governance amendment A7 (internal merge protection): no lane lands new work until main is green again. Fix forward or revert, then close this issue.' "$RUN_URL")
          gh issue create --repo "$GITHUB_REPOSITORY" \
            --title "STOP-THE-LINE: CI red on main @ ${SHORT_SHA}" \
            --body "$BODY"
