Skip to content

ci: require a CHANGELOG entry for shipped-code PRs - #27

Merged
elkaix merged 2 commits into
mainfrom
ci/changelog-entry-required
May 30, 2026
Merged

ci: require a CHANGELOG entry for shipped-code PRs#27
elkaix merged 2 commits into
mainfrom
ci/changelog-entry-required

Conversation

@elkaix

@elkaix elkaix commented May 30, 2026

Copy link
Copy Markdown
Member

Closes #26.

What

Adds .github/workflows/changelog-entry-required.yml — a pull_request check that fails when a PR touches shipped code but adds no line under ## Unreleased in CHANGELOG.md. This stops the changelog from silently drifting out of sync with main (the exact gap that left ## Unreleased empty across #17/#21/#22/#23 at the 0.26.0 release, forcing notes to be reconstructed from git log).

How it works

  • Shipped-path scope (runtime + installers): src/**, packages/**, scripts/install*.{sh,ps1}, pythinker.spec, and installer/release workflows (linux-installer, windows-installer, homebrew-tap, release-*, promote-release). Anything else (docs, sdks, examples, tests, other CI) requires no entry.
  • Detection rule: extracts the ## Unreleased block from base and head and requires ≥1 added non-blank line — so a PR adding nothing doesn't pass on bullets left by prior PRs.
  • Skips: release-prep PRs (chore(release) title or release/* head branch) that consume ## Unreleased into a dated block.
  • Escape hatches: no-changelog label or [skip changelog] in the PR body.

Design note (deliberate)

No paths: trigger filter. A path-filtered required check never reports on out-of-filter PRs, leaving them BLOCKED under branch protection with no override — the dead-required-status bug fixed in 0.26.0. So the workflow runs on every PR and matches paths inside the job, passing cleanly when no shipped path is touched. The header comment documents this so it isn't "optimized" back into the bug.

Verification

  • Maps to the issue's evidence: ran the extractor+diff against the real base/head SHAs of PR fix(agent): harden reports and edit handling #23 (8+ src/** files, empty ## Unreleased) → added=0 → the check would have failed it, as intended.
  • Unit-tested the detection rule (added vs none), the multi-line case path matcher (src/packages/installer-scripts/spec/release+promote workflows pass; docs/sdks/README don't), and all four skip conditions including an injection probe ("; rm -rf / # in the body is treated as inert data).
  • All author-controlled inputs flow through env: and are used only as quoted vars or via jq — no ${{ }} interpolation into the script (no command injection).
  • git diff failure now aborts the job (fails closed) instead of yielding an empty list that would pass open.
  • YAML validated with yaml.safe_load.

The fail path is logic-tested locally, not yet CI-exercised — this PR only adds a non-shipped workflow file, so the new check runs green on the skip path here.

Follow-up (out of scope)

To enforce, add changelog-entry-required / changelog as a required status check on main (admin-gated; enforce_admins=true).

Summary by CodeRabbit

  • Chores
    • Added an automated changelog requirement: pull requests that modify shipped/source code must add non-blank lines under "## Unreleased" in CHANGELOG.md. The check respects release-prep and explicit skip conditions and provides clear guidance when an entry is missing.

Review Change Stack

Add a changelog-entry-required workflow that fails a PR which touches
shipped code (src/**, packages/**, installer scripts, pythinker.spec,
installer/release workflows) without adding a line under ## Unreleased
in CHANGELOG.md, so the changelog stops silently drifting out of sync
with main and release notes no longer have to be back-filled from
git log under time pressure.

The check runs on every PR and matches shipped paths inside the job
(no paths: trigger filter) so it can be a required status check without
re-introducing the dead-required-status bug fixed in 0.26.0. Release-prep
PRs (chore(release) title or release/* branch) are skipped, and a
no-changelog label or [skip changelog] PR-body marker is an escape hatch.

Closes #26
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0c79f6f4-f869-4bcc-b3d0-a4f79f1b38e5

📥 Commits

Reviewing files that changed from the base of the PR and between cf41099 and e5eb148.

📒 Files selected for processing (1)
  • .github/workflows/changelog-entry-required.yml

📝 Walkthrough

Walkthrough

Adds a GitHub Actions workflow that validates PR CHANGELOG entries. The workflow triggers on pull requests, skips enforcement for release-prep PRs and explicit opt-outs, detects shipped-code changes, compares ## Unreleased blocks between base and head, and fails if no non-blank lines were added.

Changes

CHANGELOG entry enforcement for shipped-code PRs

Layer / File(s) Summary
Workflow trigger and checkout
.github/workflows/changelog-entry-required.yml
Workflow trigger definitions and repository permission; changelog job runs on ubuntu-latest and checks out the repo with full history.
PR metadata and skip logic
.github/workflows/changelog-entry-required.yml
Populates env vars from PR title/body/labels/SHAs and implements early-exit skip logic for release-prep PRs, the no-changelog label, and [skip changelog] in the PR body.
Shipped-code detection and CHANGELOG validation
.github/workflows/changelog-entry-required.yml
Diffs BASE_SHA...HEAD_SHA to detect touched shipped-code paths; if any, extracts ## Unreleased from CHANGELOG.md at base and head, diffs those sections, counts newly added non-blank lines, and fails with explicit ::error:: messages when zero are found.

Sequence Diagram

sequenceDiagram
  participant PullRequest
  participant GitHubActions
  participant GitRepo
  PullRequest->>GitHubActions: trigger pull_request events (opened/synchronize/edited, etc.)
  GitHubActions->>GitRepo: checkout (fetch-depth: 0) and read PR metadata (title, body, labels, base/head SHAs)
  GitHubActions->>GitRepo: git diff BASE_SHA...HEAD_SHA (detect changed files)
  GitHubActions->>GitRepo: git show BASE_SHA:CHANGELOG.md and git show HEAD_SHA:CHANGELOG.md (extract '## Unreleased' blocks)
  GitHubActions->>GitHubActions: diff extracted blocks and count added non-blank lines
  GitHubActions-->>PullRequest: pass or emit ::error:: messages when no changes found
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

enhancement

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commits format (type: ci, scope: changelog requirement) and accurately summarizes the workflow addition for enforcing CHANGELOG entries on shipped-code PRs.
Description check ✅ Passed Description covers objectives, design rationale, verification steps, and skip conditions comprehensively; follows the template structure with clear sections explaining what, how, and design decisions.
Linked Issues check ✅ Passed PR fully addresses issue #26 requirements: detects shipped-code path changes, requires ≥1 added line in ## Unreleased, provides skip conditions (release-prep, no-changelog label, [skip changelog] marker), and includes comprehensive verification against real PR #23.
Out of Scope Changes check ✅ Passed All changes are scoped to the new GitHub Actions workflow file and directly address issue #26; no extraneous modifications to unrelated systems.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/changelog-entry-required

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/changelog-entry-required.yml:
- Around line 27-30: Update the "Checkout repository" step that currently uses
"actions/checkout@v4" to pin to the full 40-character commit SHA for the
actions/checkout action (replace "actions/checkout@v4" with
"actions/checkout@<full-commit-sha>") and add "persist-credentials: false" under
the "with:" block (next to "fetch-depth: 0") to disable credential persistence;
target the step labeled "Checkout repository" / the uses: actions/checkout entry
to make these changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b7ffbbcf-f332-49e1-ab8b-b6cd06e516c7

📥 Commits

Reviewing files that changed from the base of the PR and between a32263f and cf41099.

📒 Files selected for processing (1)
  • .github/workflows/changelog-entry-required.yml

Comment thread .github/workflows/changelog-entry-required.yml
The changelog-entry-required job is read-only (git show/diff over
already-fetched history, no push), so it does not need the GITHUB_TOKEN
left in .git/config on the runner. Addresses CodeRabbit/zizmor artipacked.

Leaving actions/checkout pinned to @v4 to match the repo-wide convention
(all 28 checkout uses pin by tag, none by SHA); SHA-pinning belongs in a
dedicated repo-wide hardening pass, not this single-workflow PR.
@elkaix
elkaix merged commit 707817d into main May 30, 2026
26 checks passed
@elkaix
elkaix deleted the ci/changelog-entry-required branch May 30, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI: require src-touching PRs to update CHANGELOG ## Unreleased

1 participant