ci: require a CHANGELOG entry for shipped-code PRs - #27
Conversation
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
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds 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 ChangesCHANGELOG entry enforcement for shipped-code PRs
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (1)
.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.
Closes #26.
What
Adds
.github/workflows/changelog-entry-required.yml— apull_requestcheck that fails when a PR touches shipped code but adds no line under## UnreleasedinCHANGELOG.md. This stops the changelog from silently drifting out of sync withmain(the exact gap that left## Unreleasedempty across #17/#21/#22/#23 at the 0.26.0 release, forcing notes to be reconstructed fromgit log).How it works
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.## Unreleasedblock 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.chore(release)title orrelease/*head branch) that consume## Unreleasedinto a dated block.no-changeloglabel 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
src/**files, empty## Unreleased) →added=0→ the check would have failed it, as intended.casepath 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).env:and are used only as quoted vars or viajq— no${{ }}interpolation into the script (no command injection).git difffailure now aborts the job (fails closed) instead of yielding an empty list that would pass open.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 / changelogas a required status check onmain(admin-gated;enforce_admins=true).Summary by CodeRabbit