Problem
When generate_changelog runs and finds a changelog diff, create-pr opens a new randomly-suffixed branch and a new PR (chore/generate-changelog-m68pzu, -1aqpfr, -viap3f, …) rather than updating the changelog PR that is already open. While an earlier changelog PR sits unmerged, every subsequent push to main legitimately still sees a diff against main — and opens another PR for it.
The result is a queue of near-identical PRs, all requiring individual review, which then go permanently conflicting the moment a release lands (the release commit folds the Unreleased entries into a version section, so every outstanding PR now wants to re-add already-released content as unreleased).
To be clear about what is not the problem: create-pr already correctly skips PR creation when the regenerated changelog is unchanged. Verified on https://github.com/dfinity/icp-js-core/actions/runs/30821425842 — it ran on a chore: generate changelog merge, cz produced byte-identical content, and no PR was created. So this is not about no-op runs. The defect is purely branch reuse.
Evidence
dfinity/icp-js-core — 8 changelog PRs for what amounted to 2 distinct changelog states:
- #1376, #1378, #1382 — byte-identical diffs, all three adding one entry (
feat: Revamp Agent.readState (#1375)). Spawned by three separate pushes to main while the first one sat unmerged. Two closed as duplicates, one merged.
- #1363, #1368, #1369, #1372, #1373 — all permanently
CONFLICTING after v6.0.0 shipped; the content they wanted to add as Unreleased was already in the released section. All five closed as obsolete, nothing recoverable.
Oldest had been open since 2026-06-09.
dfinity/pic-js — currently 6 open (#269, #270, #272 conflicting; #274, #277, #279 mergeable), none merged since 2026-04-14. Same pattern, further along.
Notably, the repos that stay clean (icp-js-auth, icp-js-signer, icp-js-bindgen) aren't configured differently — they just release frequently enough to drain the queue. All five repos require 1 approving review with no bot bypass, so the design converts "we haven't shipped in a while" into "we have a pile of conflicting bot PRs."
Root cause
actions/create-pr appends a random suffix to branch_name, and no input exposes a way to disable it — the reusable workflow's branch_name default (chore/generate-changelog) is only ever a prefix in practice.
Possible solutions
Option A — reuse a single canonical branch (preferred)
Add an input such as reuse_branch: true (or make it the default for this workflow) so create-pr force-pushes to a fixed branch name and updates the existing open PR instead of opening a new one. One long-lived, self-updating changelog PR per repo.
Option B — swap create-pr for peter-evans/create-pull-request in this workflow
It does exactly this natively: fixed branch, updates in place, and closes the PR automatically when the diff empties. Larger change, and diverges from the shared create-pr action used elsewhere.
Option C — additionally allow auto-merge for the bot's changelog PR
Orthogonal, but worth considering: even one self-updating PR still needs a human approval per release cycle. A ruleset bypass for the PR-automation app plus auto-merge would make the changelog PR fully hands-off. This is a per-repo ruleset change rather than a ci-tools change.
Blast radius
icp-js-core, icp-js-auth, icp-js-signer, icp-js-bindgen, and pic-js all consume this reusable workflow.
Relation to #75
Separate failure mode. #75 is cz changelog exiting nonzero on release commits, which fails the job in the Generate changelog step before create-pr runs. This issue is about create-pr's branching behavior on runs where cz succeeds. Fixing either does not fix the other.
Problem
When
generate_changelogruns and finds a changelog diff,create-propens a new randomly-suffixed branch and a new PR (chore/generate-changelog-m68pzu,-1aqpfr,-viap3f, …) rather than updating the changelog PR that is already open. While an earlier changelog PR sits unmerged, every subsequent push tomainlegitimately still sees a diff againstmain— and opens another PR for it.The result is a queue of near-identical PRs, all requiring individual review, which then go permanently conflicting the moment a release lands (the release commit folds the
Unreleasedentries into a version section, so every outstanding PR now wants to re-add already-released content as unreleased).To be clear about what is not the problem:
create-pralready correctly skips PR creation when the regenerated changelog is unchanged. Verified on https://github.com/dfinity/icp-js-core/actions/runs/30821425842 — it ran on achore: generate changelogmerge,czproduced byte-identical content, and no PR was created. So this is not about no-op runs. The defect is purely branch reuse.Evidence
dfinity/icp-js-core— 8 changelog PRs for what amounted to 2 distinct changelog states:feat: Revamp Agent.readState (#1375)). Spawned by three separate pushes tomainwhile the first one sat unmerged. Two closed as duplicates, one merged.CONFLICTINGafter v6.0.0 shipped; the content they wanted to add asUnreleasedwas already in the released section. All five closed as obsolete, nothing recoverable.Oldest had been open since 2026-06-09.
dfinity/pic-js— currently 6 open (#269, #270, #272 conflicting; #274, #277, #279 mergeable), none merged since 2026-04-14. Same pattern, further along.Notably, the repos that stay clean (
icp-js-auth,icp-js-signer,icp-js-bindgen) aren't configured differently — they just release frequently enough to drain the queue. All five repos require 1 approving review with no bot bypass, so the design converts "we haven't shipped in a while" into "we have a pile of conflicting bot PRs."Root cause
actions/create-prappends a random suffix tobranch_name, and no input exposes a way to disable it — the reusable workflow'sbranch_namedefault (chore/generate-changelog) is only ever a prefix in practice.Possible solutions
Option A — reuse a single canonical branch (preferred)
Add an input such as
reuse_branch: true(or make it the default for this workflow) socreate-prforce-pushes to a fixed branch name and updates the existing open PR instead of opening a new one. One long-lived, self-updating changelog PR per repo.Option B — swap
create-prforpeter-evans/create-pull-requestin this workflowIt does exactly this natively: fixed branch, updates in place, and closes the PR automatically when the diff empties. Larger change, and diverges from the shared
create-praction used elsewhere.Option C — additionally allow auto-merge for the bot's changelog PR
Orthogonal, but worth considering: even one self-updating PR still needs a human approval per release cycle. A ruleset bypass for the PR-automation app plus auto-merge would make the changelog PR fully hands-off. This is a per-repo ruleset change rather than a ci-tools change.
Blast radius
icp-js-core,icp-js-auth,icp-js-signer,icp-js-bindgen, andpic-jsall consume this reusable workflow.Relation to #75
Separate failure mode. #75 is
cz changelogexiting nonzero on release commits, which fails the job in theGenerate changelogstep beforecreate-prruns. This issue is aboutcreate-pr's branching behavior on runs whereczsucceeds. Fixing either does not fix the other.