name: CI

# Orchestrates the CI pipeline from per-stage reusable workflows (ci-security / ci-test / ci-build)
# so each stage lives in its own file. Order: security -> test -> build. All must pass before any
# deploy workflow is enabled (deploys trigger on this workflow's success; see deploy-*.yml), and the
# full pipeline runs: security -> test -> build -> deploy -> e2e (e2e.yml, post-deploy).
#
# The build stage is disabled for feature branches, EXCEPT those targeting main: it runs on a push
# to main and on any PR whose base is main - so nothing lands on main (the dev-deploy branch)
# without a green build. Issue PRs into a milestone branch skip build and get fast security + test
# feedback.

on:
  push:
    branches: [main]
  pull_request:

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  # Path-filter gate (#788): classifies the diff so test/build jobs can skip work a PR cannot
  # have affected. On a push to main every output is forced 'true' - the full pipeline always
  # runs before anything deploys. Gated via needs + if, never top-level `on: paths:` (a check
  # skipped by a top-level path filter never reports).
  changes:
    permissions:
      contents: read
      pull-requests: read
    uses: ./.github/workflows/ci-changes.yml

  security:
    uses: ./.github/workflows/ci-security.yml

  test:
    needs: changes
    uses: ./.github/workflows/ci-test.yml
    with:
      web: ${{ needs.changes.outputs.web }}
      infra: ${{ needs.changes.outputs.infra }}
      docs: ${{ needs.changes.outputs.docs }}

  # Changelog-fragment gate (#518): every feature PR into main must add a changelog.d/
  # fragment (or opt out with an empty +misc fragment) so CHANGELOG.md is assembled from
  # per-PR files instead of top-inserts. Runs only on PRs whose base is main - not on the
  # push/merge to main, which carries no fragment.
  changelog:
    if: ${{ github.event_name == 'pull_request' && github.base_ref == 'main' }}
    uses: ./.github/workflows/ci-changelog.yml

  build:
    needs: [changes, security, test]
    if: ${{ github.ref == 'refs/heads/main' || github.base_ref == 'main' }}
    # packages: write lets the build stage push the SHA-tagged API image to GHCR on a push to main
    # (build-once, deploy-many). PRs build the image to validate but do not push.
    permissions:
      contents: read
      packages: write
    uses: ./.github/workflows/ci-build.yml
    with:
      ui: ${{ needs.changes.outputs.ui }}
