Add changelog fragment workflow to prevent merge conflicts#1281
Add changelog fragment workflow to prevent merge conflicts#1281willwashburn wants to merge 7 commits into
Conversation
Pending user-visible changes now live as one file per change under
changelog.d/ instead of being written directly into the [Unreleased]
section of CHANGELOG.md. Because each change lands in its own new file,
two PRs never edit the same lines, so a changelog entry can no longer
merge-conflict or get inserted under the wrong (already-released) version
when PRs merge in quick succession.
- scripts/changelog.mjs: zero-dep CLI with add/preview/check/release.
Fragments carry a `type` (Keep a Changelog section) and `level` (SemVer
impact); the release version bump is the highest level across fragments.
`release` compiles fragments into a dated version section and deletes
them, merging any inline [Unreleased] bullets for the transition.
- package.json: changelog:{add,preview,check,release} scripts.
- .github/workflows/changelog.yml: validates fragments and guards against
leftover conflict markers in CHANGELOG.md on every PR.
- .gitattributes: CHANGELOG.md merge=union as a backstop.
- changelog.d/README.md + AGENTS.md: document the workflow.
- Migrated the existing [Unreleased] entry to a fragment and reset the
heading to an empty [Unreleased].
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157j54yBsE4a3KeDdFJ1TRj
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughIntroduces a fragment-based changelog workflow with CLI commands for authoring, previewing, validating, collecting, and releasing entries. CI validates fragments, while publishing collects them into the root changelog. ChangesChangelog fragments
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant PullRequest
participant ChangelogWorkflow
participant ChangelogCLI
participant PublishWorkflow
participant ChangelogFile
PullRequest->>ChangelogWorkflow: trigger changelog check
ChangelogWorkflow->>ChangelogCLI: validate fragments and conflict markers
PublishWorkflow->>ChangelogCLI: collect fragments for a release
ChangelogCLI->>ChangelogFile: merge entries into [Unreleased]
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3d2d43e3a6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Describe the fragment workflow in present-tense terms rather than framing it against the previous approach; trim to the essentials. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157j54yBsE4a3KeDdFJ1TRj
There was a problem hiding this comment.
All reported issues were addressed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="AGENTS.md">
<violation number="1" location="AGENTS.md:49">
P2: The documentation describes `changelog:release` as the mechanism for compiling fragments into a dated section at release time, but `.github/workflows/publish.yml` still extracts changelog entries from the inline `[Unreleased]` block in `CHANGELOG.md`. Since this PR intentionally leaves `[Unreleased]` empty and moves entries into `changelog.d/`, automated releases will omit the curated notes and leave fragment files behind unless the publish workflow is updated to invoke `npm run changelog:release` (or equivalent) before committing the release.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
…e-conflicts-tfuopz
- publish.yml: add a "Collect changelog fragments" step that folds changelog.d/ fragments into the inline [Unreleased] block (and deletes them) before the existing changelog generator runs, so released notes include curated fragments instead of leaving them behind. Gated to stable releases; stages changelog.d/ removals in the release commit. - scripts/changelog.mjs: add `collect` subcommand backing that step (no-op when there are no fragments). - Migrate the pending inline [Unreleased] entries (carried in from main) into fragments and reset [Unreleased] to empty, resolving the merge. - AGENTS.md: escape backticks in the changelog:add example so copy-paste doesn't trigger shell command substitution. - changelog.d/README.md: list `type` values in render order. - Tighten the observer-token fragment to an impact-first one-liner. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157j54yBsE4a3KeDdFJ1TRj
|
Addressed the review feedback and resolved the merge conflict. Publish workflow (P1 — flagged by codex + cubic): valid and now fixed. Other comments:
Merge conflict: the Generated by Claude Code |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/changelog.yml (1)
13-13: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueSet
persist-credentials: falseon the checkout action.By default,
actions/checkoutpersists the GitHub token to the local git config. Since this workflow only runs a local validation script and does not need to push commits back to the repository, settingpersist-credentials: falseis a good security hygiene practice to adhere to the principle of least privilege.💡 Proposed fix
- - uses: actions/checkout@v4 + - uses: actions/checkout@v4 + with: + persist-credentials: false🤖 Prompt for 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. In @.github/workflows/changelog.yml at line 13, Update the actions/checkout@v4 step in the changelog workflow to set persist-credentials to false, preventing unnecessary GitHub token persistence while leaving the rest of the workflow unchanged.Source: Linters/SAST tools
🤖 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.
Nitpick comments:
In @.github/workflows/changelog.yml:
- Line 13: Update the actions/checkout@v4 step in the changelog workflow to set
persist-credentials to false, preventing unnecessary GitHub token persistence
while leaving the rest of the workflow unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a69aa693-049a-42b0-a5a4-f7680cbd9a04
📒 Files selected for processing (11)
.gitattributes.github/workflows/changelog.yml.github/workflows/publish.ymlAGENTS.mdCHANGELOG.mdchangelog.d/README.mdchangelog.d/broker-panic-telemetry.mdchangelog.d/observer-token-name-conflict.mdchangelog.d/sdk-repo-filtered-placement.mdpackage.jsonscripts/changelog.mjs
There was a problem hiding this comment.
1 issue found across 8 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/changelog.mjs">
<violation number="1" location="scripts/changelog.mjs:372">
P3: Publish-time `collect` now maintains a second copy of the release merge/rebuild algorithm. Extract the shared fold/rebuild helper so fixes to `[Unreleased]` parsing or formatting apply consistently to both release paths.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| return; | ||
| } | ||
|
|
||
| const changelog = readFileSync(CHANGELOG, 'utf8'); |
There was a problem hiding this comment.
P3: Publish-time collect now maintains a second copy of the release merge/rebuild algorithm. Extract the shared fold/rebuild helper so fixes to [Unreleased] parsing or formatting apply consistently to both release paths.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/changelog.mjs, line 372:
<comment>Publish-time `collect` now maintains a second copy of the release merge/rebuild algorithm. Extract the shared fold/rebuild helper so fixes to `[Unreleased]` parsing or formatting apply consistently to both release paths.</comment>
<file context>
@@ -354,6 +354,54 @@ function cmdRelease(argv) {
+ return;
+ }
+
+ const changelog = readFileSync(CHANGELOG, 'utf8');
+ const byType = parseUnreleasedBody(changelog);
+ for (const f of fragments) {
</file context>
…e-conflicts-tfuopz
main cut v10.6.0, which compiled the broker-panic, repo-filtered placement, and observer-token entries into the released section. Those same changes were carried as pending fragments on this branch; remove them so they aren't released a second time. Merge with main also brought in the version bump to 10.6.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157j54yBsE4a3KeDdFJ1TRj
Document the remaining command/helper functions in scripts/changelog.mjs (add, preview, check, release, help, and the slug/flag/bump helpers) to match the repo's JSDoc convention. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157j54yBsE4a3KeDdFJ1TRj
Summary
Fixes the recurring changelog pain: when several PRs are open at once, one merges and gets a release, and the next PR's changelog entry lands under the newly-released version (or leaves a conflict marker) instead of under
[Unreleased]. Root cause is that every PR edits the same few lines of one file, so git's 3-way merge anchors additions to stale context.This moves pending user-visible changes to one file per change under
changelog.d/. Because each change lands in its own new file, two PRs never touch the same lines — so a changelog entry can't merge-conflict or be inserted under the wrong version. At release time the fragments compile into a dated version section and are deleted.What's included
scripts/changelog.mjs— zero-dependency CLI:add— scaffold a fragment (--type,--level, text).preview— render what[Unreleased]will look like from the fragments.check— validate every fragment and reject leftover conflict markers inCHANGELOG.md(CI entry point).release— compile fragments into## [x.y.z] - DATE, delete them, reset[Unreleased]to empty. Version defaults to bumpingpackage.jsonby the highest fragment level (patch < minor < major); also folds in any inline[Unreleased]bullets so the transition is safe.package.json—changelog:{add,preview,check,release}scripts..github/workflows/changelog.yml— runschangelog checkon every PR..gitattributes—CHANGELOG.md merge=unionas a backstop against markers if the file is ever edited directly.changelog.d/README.md+AGENTS.md— document the format and replace the old "manually bump[Unreleased - Patch]" convention (the level is now derived from fragments).[Unreleased]entry into a fragment and reset the heading to an empty[Unreleased](dogfood).Fragment format:
Test Plan
changelog:addgenerates prettier-clean fragments (verified againstprettier --check).changelog:previewrenders correct section ordering and derives[Unreleased - Major]when a major fragment is present.changelog:release --version 10.5.1produces an empty[Unreleased]+ a new## [10.5.1]section with the compiled entry, leaving prior versions intact.changelog:checkexits non-zero on an invalidtype/leveland on a conflict marker inCHANGELOG.md; exits 0 on the clean tree.changelog checkjob.Screenshots
🤖 Generated with Claude Code
https://claude.ai/code/session_0157j54yBsE4a3KeDdFJ1TRj
Generated by Claude Code