Skip to content

fix(release): repair the release PR heading normaliser and lockfile sync - #274

Merged
gitfromwildan merged 3 commits into
masterfrom
fix/release-please-rebase-and-changelog-gate
Oct 16, 2026
Merged

gitfromwildan merged 3 commits into
masterfrom
fix/release-please-rebase-and-changelog-gate

Conversation

@gitfromwildan

Copy link
Copy Markdown
Member

Summary

fix: repair the release-PR heading normaliser so the release PR stops failing CI, and rebase the release branch on every master push

The open release PR (#273) was failing the lint job with:

Error: CHANGELOG.md missing section '## v0.2.0' (expected '## v0.2.0 — ' or '## v0.2.0 (')

The cause was not the changelog content — it was that the step meant to normalise the heading had never matched anything, and failed silently. Fixing that exposed two adjacent bugs that had been masking each other, plus a structural gap in how the release branch is kept in sync with master.

🐛 Bug Fixes

  • fix(release): match both release-please changelog dialects in the heading normaliser. Release-please emits the github dialect here — ## [0.2.0](https://…/compare/v0.1.8...v0.2.0) (2026-10-16) — but the step searched for the literal ## 0.2.0 (, from the default dialect. It never matched, so it printed "heading already normalised (or not found)" and exited 0. The un-normalised heading then shipped to ci.yml, whose gate keys on the v prefix and rejected it. The pattern is now dialect-agnostic: the link target is matched loosely because the compare URL contains its own parentheses, and the version boundary is anchored strictly so a sibling section such as ## 0.2.01 or ## 0.2.0-rc.1 is not mistaken for this release.
  • fix(release): fail loudly when no heading matches. The old step treated "not found" as success, which is precisely how a broken normaliser stayed invisible for a whole release cycle. A miss is now an error and exits 1.
  • fix(ci): read tauri.conf.json through JSON instead of grep -A2 '^version'. The version key is indented ( "version": "0.1.8"), so the anchored grep never matched and silently produced an empty string; [ "$npm_v" = "" ] was simply false, so that file was skipped without any signal. The same bug existed in the sync-lockfiles job's sync_root_version, where the empty result was substituted into an awk rewrite.
  • fix(ci): reject an empty version extraction. A blank reading now fails the gate with an explicit message instead of being treated as a comparison result, so a manifest that moves or changes format surfaces immediately.
  • fix(release): resolve the release PR branch by label instead of from the action output. sync-lockfiles was gated on needs.release-please.outputs.prs_created == 'true', but that output is only true when a PR was opened — on a rebase of an existing PR the action reports false and emits no pr output at all, so the job that repairs the branch was skipped in exactly the case it exists to handle. It now runs after every successful release-please run and resolves the branch via autorelease: pending.
  • fix(release): use grep -m1 rather than grep … | head -1 for version extraction, avoiding a SIGPIPE under set -o pipefail.

🚀 Features

  • feat(release): rebase the release branch on every push to master via always-update. Release-please only rewrites the release PR when its generated body changes, so any master commit producing no changelog line — docs, test and chore are all hidden in changelog-sections — left the PR stale against master with no signal. With always-update set, release-please rebuilds the branch on the new master head and force-updates the ref. This is a root-level manifest option and is deliberately not read from packages.

🧪 Testing

  • fix: Validate with node test/check-changelog-heading.mjs — new guard. It extracts the heading pattern out of the workflow source (so it cannot drift from what actually runs) and asserts both dialects, the near-misses that must not match, date capture, idempotency, the loud-failure marker, and that the ci.yml gate accepts the normalised output. Confirmed the guard fails when the original buggy pattern is restored, and passes when the fix is in place.
  • fix: Validate with node test/check-release-config.mjs — still passes; the new always-update key is accepted and the manifest/package.json agreement check is unaffected.
  • fix: Validate with node test/check-acl.mjs and node test/check-docker-paths.mjs — both pass.
  • fix: Validate with npx oxlint frontend/ test/__fixtures__/ — 0 warnings, 0 errors across 197 files.
  • fix: Validate with npx tsc -b — clean.
  • fix: Validate both workflows parse as YAML (npx js-yaml) and that the config file still satisfies JSON.parse, since release-please-config.json is read with a strict JSON parser.
  • fix: Validate the normaliser end-to-end against the live release-PR branch: the heading becomes ## v0.2.0 — 2026-10-16, the older ## v0.1.8 section is untouched, the ci.yml gate passes, and a second run is a no-op.
  • fix: Validate the version gate against both trees — master (all seven values 0.1.8) and the release-PR branch (all seven 0.2.0) — and that it now rejects an empty extraction.

🔄 Refactor

  • feat: correct the release-workflow documentation in CONTRIBUTING.md, which claimed release-please updates the PR "on every push to master" — it did not, and now does because of always-update. Documents that the rebase is a git tree + updateRef force push rather than a merge, that always-update is a root-level option, and that the heading rewrite fails loudly if release-please changes its format.
  • feat: explain in ci.yml why the changelog gate accepts more than one dialect, and that the release PR is normalised before it reaches the gate.

Notes

Two deliberate design decisions worth reviewing:

  • --force-with-lease was intentionally not used for the sync-lockfiles push. That commit is always built on the head just checked out, so a plain push is a fast-forward. --force-with-lease compares against the checkout's stale remote-tracking ref rather than the live head, so against release-please's own force-push it is a no-op guard — and it would only ever be "protecting" a commit we did not write. A rejected push is the correct outcome there: it means release-please rebased underneath us and re-running the job rebuilds the commit. The reasoning is recorded in the workflow comments.
  • always-update changes the release PR into a moving target. Every master push now force-rewrites the release branch. That is what makes the sync-lockfiles repair reliable, but if a stable release PR is preferred instead, this is the one line to drop.

Known limitation (unchanged, pre-existing)

A push made with GITHUB_TOKEN does not trigger other workflows, so the sync-lockfiles commit still will not re-run ci.yml on the release PR — the checks run on the PR as release-please opened it. This was already documented at release-please.yml L57–63 and is not made worse here, but the loop stays only partly verified until a PAT or GitHub App token is supplied via secrets.RELEASE_PLEASE_TOKEN.

Comment thread test/check-changelog-heading.mjs Fixed
Comment thread test/check-changelog-heading.mjs Fixed
@pullfrog

pullfrog Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixed and pushed commit 49e5207 to PR #274. The CodeQL failure was introduced by test/check-changelog-heading.mjs:125, where "\." was flagged as a useless escape; the guard now substitutes "\\." so the generated regex matches literal version dots. Verified with node test/check-changelog-heading.mjs, node test/check-release-config.mjs, node test/check-acl.mjs, node test/check-docker-paths.mjs, npx oxlint frontend/ test/__fixtures__/, npx tsc -b, and npm test — all passed. YAML parsing was not run because js-yaml is unavailable in this environment.

Task list (5/5 completed)

Pullfrog  | View workflow run | via Pullfrog | Using gpt-6-luna | 𝕏

Signed-off-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>

@pullfrog pullfrog 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.

Important

The release branch is not guaranteed to be rebased on every master push as documented; hidden-only pushes can still leave the existing release PR stale.

Reviewed changes

This review covers the CI version-gate fixes, release-please workflow/configuration changes, release documentation, and the new changelog-heading guard.

  • Version gate — reads the Tauri version through JSON, rejects empty extractions, and avoids grep/head pipeline failures.
  • Release synchronization — resolves the open release PR by label, synchronizes lockfiles, normalizes both changelog heading dialects, and pushes the repair commit.
  • Release cadence — adds root-level always-update and documents the release branch as being rebuilt on every master push.
  • Regression guard — tests the heading matcher, date capture, near-miss rejection, idempotency, and CI gate compatibility.

Targeted verification run: node test/check-changelog-heading.mjs, node test/check-release-config.mjs, and YAML/JSON parsing all passed. The full frontend/Rust chains were not run because this PR changes only CI/release automation and documentation.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6-luna | 𝕏

Comment thread release-please-config.json

@pullfrog pullfrog 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.

Important

The incremental fix is correct, but the prior release-branch freshness issue remains unresolved: always-update does not cause release-please to process an existing PR when a master push contains only hidden commit types, so the documented every-push rebase guarantee is still not met.

Reviewed changes

This incremental review covers the changelog guard correction landed since the prior Pullfrog review.

  • Escaped dotted versions — Updated the guard's substituted version to preserve literal dots when it constructs the CI gate RegExp, preventing false matches for sibling version headings.
  • Validated the guard — Confirmed node test/check-changelog-heading.mjs passes with the corrected pattern.

⚠️ Hidden-only pushes can leave the release branch stale

always-update only affects release-please's update decision after it has a release candidate to process. Because docs, test, and chore are hidden, a push containing only those commit types can leave an existing release branch behind master, despite the workflow and documentation claiming unconditional synchronization.

Technical details
# Hidden-only pushes can leave the release branch stale

## Affected sites
- `release-please-config.json:9` — `always-update` does not create a candidate for hidden-only pushes.
- `.github/workflows/release-please.yml:28-30` — the workflow triggers for every `master` push but does not itself rebase the existing branch when release-please has no candidate.
- `CONTRIBUTING.md:178-186` — documents unconditional branch rebuilding.

## Required outcome
- Either explicitly synchronize the existing release branch on every successful `master` push, including hidden-only pushes, or narrow the configuration and documentation claim to pushes for which release-please builds a candidate.

Pullfrog  | Fix it ➔ | View workflow run | Using gpt-6-luna | 𝕏

@pullfrog
pullfrog Bot deployed to build-approval October 16, 2026 05:23 Active

@pullfrog pullfrog 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.

✅ Pullfrog addressed all of its review feedback on this PR.

Addressed the review’s hidden-only push gap in 1bb23ea. The release synchronization job now rebases the labeled release branch onto origin/master on every successful run, force-updates only when needed, and the documentation plus release-config guard describe and verify the behavior. Targeted release guards, changelog guard, YAML/JSON validation, and whitespace checks passed; the commit was pushed and the review thread was replied to and resolved.

Task list (4/4 completed)
  • Check repository guidance and durable learnings
  • Checkout PR 274 and inspect review 5543353758
  • Implement and verify all actionable review fixes
  • Commit, push, reply to threads, and report results

Pullfrog  | View workflow run | Using gpt-6-luna | 𝕏

@pullfrog
pullfrog Bot deployed to build-approval October 16, 2026 05:25 Active
@pullfrog
pullfrog Bot deployed to build-approval October 16, 2026 05:25 Active

@pullfrog pullfrog 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.

✅ Pullfrog addressed all of its review feedback on this PR.

Review 5543385701 has no open inline threads. Its required hidden-only push fix is already present on PR 274 in commit 1bb23ea: the workflow resolves the labeled release branch, rebases it onto origin/master on every successful run, force-updates only when needed, and includes config/documentation regression coverage. Targeted changelog and release-config guards, workflow/config parsing, and whitespace validation pass; the branch is clean and no additional push was necessary.

Task list (4/4 completed)
  • Check repository guidance and review metadata
  • Checkout PR 274 and inspect all review threads
  • Implement and test every actionable review comment
  • Commit, push, reply to threads, and verify clean tree

Pullfrog  | View workflow run | Using gpt-6-luna | 𝕏

@gitfromwildan gitfromwildan self-assigned this Oct 16, 2026
@gitfromwildan
gitfromwildan merged commit 22a89bb into master Oct 16, 2026
10 checks passed
@gitfromwildan
gitfromwildan deleted the fix/release-please-rebase-and-changelog-gate branch October 16, 2026 05:58

This branch was successfully deployed

1 active deployment
build-approval — 1bb23ea6 Deployed Oct 16, 2026 by pullfrog[bot]
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.

2 participants