# Validates the changelog FRAGMENT for non-trivial PRs. See GIT_FLOW.md.
#
# Entries live in `changelog.d/` as one file per PR, not as a line in a shared
# `## [Unreleased]` block -- that block was a single anchor every open PR wrote
# to, so concurrent PRs conflicted by construction.
name: changelog

on:
  pull_request:
    types: [opened, synchronize, reopened, labeled, unlabeled]

# Not cancel-in-progress, matching pr-title, pr-body and branch-name. This
# workflow reacts to `labeled` and `unlabeled`, which do not move the head, so
# a cancelled run lands on the SAME commit as the successful one -- and branch
# protection can read the cancelled one, leaving a pull request mergeable:true
# and blocked with nothing failing (#1250). Cancelling is safe where it happens
# because the head moved; here it is not.
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: false

permissions:
  contents: read
  pull-requests: read

jobs:
  check:
    runs-on: ubuntu-latest
    if: ${{ !startsWith(github.head_ref, 'release-please--') }}
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
        with:
          fetch-depth: 0

      # The check renders each added fragment rather than only looking for it,
      # so a malformed one fails here instead of at release assembly.
      - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
        with:
          python-version: "3.11"

      - name: Run changelog check
        env:
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
          PR_LABELS: ${{ join(github.event.pull_request.labels.*.name, ',') }}
          # Read as data, never interpolated into the shell: a PR title is
          # attacker-controlled text.
          PR_TITLE: ${{ github.event.pull_request.title }}
        run: bash scripts/check_changelog.sh
