ci(#1104): keep next package.json in sync with the last published release (#1109)

* ci(#1104): sync next package.json version to the last published release

next rested on a -dev stream per ADR-660 (1.3.1-dev.0) — a never-published
placeholder that leaked to source/dev installs. Make every release type write
its exact published version back to next:

- finalize/hotfix (push main): auto-backmerge sets next's version to main's
  released version, folded into the existing back-merge PR (+ pinned setup-node).
- rc (no main push): the rc job opens + admin-merges a sync PR after publish.

Shared, fail-closed scripts/sync-next-version.cjs stamps package.json + the
runtime manifests via the npm version hook and refuses any non-release version.
Amends ADR-660 (supersedes the -dev stream decision).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ci(#1104): harden next-version sync against post-publish failure modes

Review hardening (Codex + code-review gates) on the #1104 sync helper and
its workflow callers:

- release.yml rc Sync step: continue-on-error so a post-publish sync hiccup
  cannot fail an already-published release (npm immutability would block re-run).
- auto-backmerge.yml inline sync: set -euo pipefail + validate VERSION before
  any shell use (closes a ${VERSION}-in-commit-message injection vector); git
  add -u instead of -A.
- sync-next-version.cjs: reuse an existing open PR instead of failing gh pr
  create on rc re-runs; regex-parse the PR number and fail loud; discriminate
  the git diff --cached --quiet exit code (only status 1 == has-diff, else
  rethrow); git add -u to avoid sweeping runner artifacts into next; tolerate
  already-merged on admin merge.
- tests: +2 (existing-PR reuse, non-diff rethrow); 14/14 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-12 13:29:45 -04:00
committed by GitHub
parent c70842b6df
commit 7f1d49935c
5 changed files with 433 additions and 0 deletions

View File

@@ -151,3 +151,26 @@ right; only the *movable placeholder* mechanic was wrong.
*(Recommend: keep the rc tags — harmless, immutable, and they anchor the GitHub prerelease.)*
3. `-dev` floor increment: next-patch (`A.B.(C+1)-dev.0`, the precedence-safe default above) or
next-minor (`A.(B+1).0-dev.0`)? *(Recommend: next-patch floor.)*
## Amendment (2026-06-12, #1104): `next` tracks the last published release
**Supersedes** the §2 / "Resolved by maintainer" choice to rest `next` on a `-dev` stream.
The `-dev` floor (e.g. `1.3.1-dev.0`) was never published to npm, yet it became the
source-of-truth version on the default branch and leaked to the real world via source/dev
installs that report `package.json`'s version — a version no release ever bore. To eliminate
phantom versions, `next` now **rests at the last published release** and is synced
automatically by the release pipeline for **every** release type:
- **finalize / hotfix** (these push `main`): the existing `main → next` back-merge
(`.github/workflows/auto-backmerge.yml`) sets `next`'s version to `main`'s released version,
folded into the same back-merge PR.
- **rc** (publishes a pre-release to the `release/<version>` branch + `@next`; does **not** push
`main`): the `rc` job in `.github/workflows/release.yml` opens and admin-merges a
`chore: sync next package version` PR after a confirmed publish.
Both paths share `scripts/sync-next-version.cjs`, which sets `package.json` and stamps the
runtime manifests (`plugin.json`, `gemini-extension.json`) via the `version` lifecycle hook,
and **refuses any non-release version string** (fail-closed — a `-dev`/placeholder can never be
written to `next` again). Open question 3 (the `-dev` floor increment) is therefore moot: there
is no `-dev` floor.