name: CI · Changelog

# Reusable changelog-fragment gate: fails a feature PR into `main` that adds no changelog
# fragment under changelog.d/ (issue #518). Adopting a per-PR fragment file - assembled into
# CHANGELOG.md at release by towncrier - is what kills the CHANGELOG top-insert merge-conflict
# class; this gate keeps the workflow honest. Called by ci.yml, which only invokes it for
# pull_request events whose base is `main` (never on push/merge to main, never on release PRs
# that edit only CHANGELOG.md itself). Changes that legitimately need no changelog opt out with
# an empty `+<slug>.misc.md` fragment (see towncrier.toml / AGENTS.md "Quality gates").

on:
  workflow_call:

permissions:
  contents: read

jobs:
  changelog:
    name: Changelog fragment
    runs-on: bloom-arc
    steps:
      - uses: actions/checkout@v4
        with:
          # Full history + the base ref so the gate can diff the PR against origin/main.
          fetch-depth: 0

      - name: Fetch base branch
        run: git fetch --no-tags origin main

      # The `towncrier check` twin in plain git/bash (#806: the gate outlived the Python
      # toolchain that used to run it; towncrier itself still assembles CHANGELOG.md at
      # release, run locally via uvx). Same semantics: pass when the diff touches a fragment
      # under changelog.d/ (the types come from towncrier.toml), skip (pass) when the only
      # changes are CHANGELOG.md or changelog.d/ itself (the release PR), and fail when code
      # changed but no fragment was added - the case this gate exists to catch.
      - name: Require a changelog fragment
        run: |
          set -euo pipefail
          changed="$(git diff --name-only origin/main...HEAD)"
          if [ -z "$changed" ]; then
            echo "no changes against origin/main; skipping"
            exit 0
          fi
          non_changelog="$(grep -vE '^(CHANGELOG\.md$|changelog\.d/)' <<<"$changed" || true)"
          if [ -z "$non_changelog" ]; then
            echo "only CHANGELOG.md/changelog.d/ changed (release PR shape); skipping"
            exit 0
          fi
          fragments="$(grep -E '^changelog\.d/[^/]+\.(added|changed|deprecated|removed|fixed|security|misc)(\.md)?$' <<<"$changed" || true)"
          if [ -n "$fragments" ]; then
            echo "changelog fragment(s) found:"
            echo "$fragments"
            exit 0
          fi
          echo "::error::No changelog fragment. Add changelog.d/<issue>.<type>.md (types: added/changed/deprecated/removed/fixed/security), or opt out with an empty +<slug>.misc.md - see towncrier.toml / AGENTS.md 'Quality gates'."
          exit 1
