Skip to content

ci(release): catch missing stable npm tags without failing in-flight publishes#6118

Merged
SivanCola merged 3 commits into
esengine:main-v2from
SivanCola:ci/release-npm-freshness-check
Jul 6, 2026
Merged

ci(release): catch missing stable npm tags without failing in-flight publishes#6118
SivanCola merged 3 commits into
esengine:main-v2from
SivanCola:ci/release-npm-freshness-check

Conversation

@SivanCola

@SivanCola SivanCola commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

#5822 的流程性根因修复。排查结论:

立即止血(已执行):推了 npm-v1.17.5 tag(指向与 v1.17.5 相同的 commit 221a764),release-npm.yml 走 build.mjs 的稳定版路径,已发布 1.17.5 并把 latest 从 0.53.2 移过去;workflow 自带的 verify 步骤已断言 tag 落位。

流程防线(本 PR):在稳定版 CLI 发布(release.yml,v* 非预发布)末尾加 npm 渠道守门:

  • 先检查匹配的 npm-v<version> tag 是否存在;不存在时 hard fail,并给出补救命令。这覆盖 [Bug]: latest dist-tag is stuck at 0.53.2 — pnpm update -g / npm update -g downgrades users to a months-old version #5822 的真正缺口:稳定版 npm tag 根本没推,release-npm.yml 的 verify run 不会发生。
  • 如果 npm-v<version> tag 已推,但 npm latest 仍低于本次版本,则短轮询后只 warning 放行。这个状态可能只是 npm workflow 仍在等待 release environment 审批、发布中,或 registry dist-tag 尚未传播;最终落位由 release-npm.yml 自己的 verify step 断言。
  • 预发布跳过;latest 等于或高于本次 tag 则通过。

Verification

  • YAML 解析通过;本地验证了 tag 缺失分支会失败,tag 已存在时 stale/equal/newer 三种 dist-tag 比较行为符合预期。
  • npm view reasonix dist-tags 已显示 latest: 1.17.5;止血发布完成。

Cache impact

Cache-impact: none - release workflow only; no runtime code.
Cache-guard: not applicable.
System-prompt-review: N/A

Fixes #5822.

v1.17.5 shipped as binaries and Homebrew while the npm `latest`
dist-tag still pointed at 0.53.2 (esengine#5822) — every `npm update -g` /
`pnpm update -g` user was silently downgraded to a months-old version.
The npm line is triggered by its own tag namespace (npm-vX.Y.Z), and
the stable npm tag was simply never pushed: 1.0.0 through 1.17.5 all
went to npm as -rc.1 prereleases under `next`. release-npm.yml's verify
step (added for esengine#5822) only guards runs that happen; nothing caught the
run that DIDN'T.

Add a freshness gate to the stable CLI release: after the public smoke,
compare `npm view reasonix dist-tags.latest` against the version being
released (sort -V). A stale `latest` fails the release with the exact
remediation (push the npm-vX.Y.Z tag, or `npm dist-tag add` for an
already-published version). Prereleases skip — npm latest does not move
on prereleases. A `latest` NEWER than the tag passes, so re-releasing
an older CLI tag is not blocked.
@SivanCola SivanCola requested a review from esengine as a code owner July 6, 2026 17:00
@github-actions github-actions Bot added v2 Go rewrite (1.x) — main-v2 branch, active development updater Auto-update / installer / release packaging labels Jul 6, 2026
The migration guide and release runbook still documented the retired
"latest stays pinned to 0.x, v2 lives under @next" policy — the exact
policy that caused esengine#5822. Update both to the current reality:

- MIGRATING.md: bare `npm i -g reasonix` installs the current 1.x
  stable; @next is the rc channel; 0.x stays installable by pinning
  [email protected].
- RELEASING.md: channels table shows latest = current 1.x stable with
  next/canary as pre-release buffers; the stable-ship step notes the
  npm-v* tag moves `latest` automatically and must not be skipped
  (release.yml now fails when npm latest lags); drop the manual
  "promote to default install" step — promotion is automatic.
@SivanCola

Copy link
Copy Markdown
Collaborator Author

追加 docs 同步(8b6fa8c):MIGRATING.md 和 RELEASING.md 仍在描述已退役的「latest 钉在 0.x、v2 走 @next」策略——正是造成 #5822 的那份文档。已更新为现状:裸 npm i -g reasonix 装当前 1.x 稳定版、@next 是 rc 通道、0.x 需 pin 版本安装;发版 runbook 的 channels 表和 ship-stable 步骤同步修正(npm-v* tag 自动晋升 latest、不可跳过——release.yml 现在会拦),删除了已自动化的手动 promote 步骤。官网(docs/index.html)和 README 检查过无需改动——它们只写 npm i -g reasonix,该命令在修复后语义恰好从「装 0.53.2」变成了「装 1.17.5」,文案本身已正确。

Review catch: the freshness check raced normal releases. The runbook
pushes v*/npm-v*/desktop-v* together, the two workflows wait on the
release environment independently, and npm dist-tags propagate
asynchronously — so a single read of dist-tags.latest could fail the
CLI release while the npm publish was merely awaiting approval or
propagating, telling the operator to push a tag that was already
pushed.

Split the check into the two states the review named:
- npm-v<version> tag missing (git ls-remote) -> hard fail. This is the
  esengine#5822 gap: nobody released to npm at all.
- tag pushed but latest lagging -> poll 6x10s (matching release-npm's
  own verify cadence), then WARN and pass: the publish may still be
  awaiting its environment approval, and release-npm.yml's verify step
  owns asserting the dist-tag lands.

RELEASING.md wording updated to match (fails on missing tag; pending
publish only warns).
@SivanCola

Copy link
Copy Markdown
Collaborator Author

Valid P1 — fixed in d23d347.

The race is real: the runbook pushes all three tags together, release.yml and release-npm.yml wait on the release environment independently, and npm applies dist-tags asynchronously (release-npm's own verify polls 6× for exactly that reason). A single registry read in the CLI job could fail a perfectly normal release mid-flight and tell the operator to push a tag that was already pushed.

Reworked into the two states the review named, with different responses:

  • npm-v<version> tag missing (checked via git ls-remote) → hard fail. This is the actual [Bug]: latest dist-tag is stuck at 0.53.2 — pnpm update -g / npm update -g downgrades users to a months-old version #5822 gap — nobody released to npm at all — and it can never be a race: if the operator followed the runbook, the tag exists by the time the CLI workflow starts.
  • Tag pushed but latest lagging → poll 6×10s (matching release-npm's verify cadence), then warn and pass. The npm publish may still be awaiting its own environment approval or propagating; asserting the dist-tag actually lands is release-npm.yml's verify step's job, so the responsibilities don't overlap and a slow approval can't produce a false red.

Three-state logic verified against the live registry: missing tag (npm-v9.9.9) → fail path; pushed+landed (npm-v1.17.5, latest=1.17.5) → pass; pushed+lagging (simulated 0.53.2 vs 1.17.5) → warn path. YAML parse clean. RELEASING.md wording updated to match (fails on missing tag; pending publish only warns).

@SivanCola SivanCola changed the title ci(release): fail a stable CLI release when npm latest lags behind ci(release): catch missing stable npm tags without failing in-flight publishes Jul 6, 2026
@SivanCola SivanCola merged commit 3a5b4d9 into esengine:main-v2 Jul 6, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

updater Auto-update / installer / release packaging v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: latest dist-tag is stuck at 0.53.2 — pnpm update -g / npm update -g downgrades users to a months-old version

1 participant