Skip to content

ci(release): unblock the two gates that fail every release PR (#4894) - #4896

Merged
os-zhuang merged 1 commit into
mainfrom
claude/ci-errors-i1t8fi
Aug 3, 2026
Merged

ci(release): unblock the two gates that fail every release PR (#4894)#4896
os-zhuang merged 1 commit into
mainfrom
claude/ci-errors-i1t8fi

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4894。修 #4422(chore: version packages (rc))上的两处红灯 —— 两处都是闸门自身的缺陷,不是该发布 PR 的内容问题,并且每一个发布 PR 都会重现

1. Check Changeset 对发布 PR 结构性必失败

闸门数的是「本 PR 新增了几个 changeset」(git diff --diff-filter=A 对 base)。这个口径对普通 PR 是对的 —— #3373 正是因为全局 find | wc -l 在 RC 预发布模式下永远非空、永远不能变红才改成这样的。但 changesets 的发布 PR 是消费侧:它把待发布的 changeset 应用成版本号和 CHANGELOG,自己按定义新增数为 0。

##[error]This PR adds no changeset. Run 'pnpm changeset' ...

发布 PR 由 github-actions[bot] 推送,不会有人去给它打 skip-changeset 标签,于是 mergeable_state: blocked 一直挂着 —— 卡在一个原理上不可能满足的检查上。

改为在 job 级豁免 changeset-release/main,分支名和作者一起钉,这样手工推一个同名分支也拿不到这个逃生口。

2. Scaffold E2E / Scaffold with repo dist 在 RC 窗口把协议大版本对错了

install 步骤本来就有兜底:仓库版本尚未发布时(@objectstack/cli@^17.0.0-rc.2 → ETARGET),把所有 @objectstack/* 改写成 latest 再装一次。但兜底只改依赖、没改 manifest —— 脚手架模板的 objectstack.config.tsscripts/sync-template-versions.mjs 在版本时刻死了仓库自己的协议大版本 engines: { protocol: '^17' },而 17 的 RC 窗口里 latest 仍指向 16.x。ADR-0087 D1 握手于是正确地拒绝启动:

✗ package 'e2e-app' targets protocol ^17 (engines.protocol) but this runtime is protocol 16.0.0
##[error]server never became healthy

也就是说这是闸门在正常工作,拦下的是这一步自己引入的偏移。同一个 workflow 的 Docker 步骤早就认识到这一类偏移(它读取实际解析到的 CLI 版本来 pin 运行时镜像,而不是硬编码 latest),只是 boot 这条路没做对应的对齐。

兜底分支现在在第二次 npm install 之后,把 engines.protocol 重新盖成实际装上的大版本,取自 node_modules/@objectstack/spec(PROTOCOL_VERSION 与该包自身 major 锁步,由 protocol-version.test.ts 守着),并打一条 ::notice,让日志能看出这一轮跑的是降级后的协议版本,而不是静默改写。

三点边界是刻意的:

  • 只在兜底分支里改。正常路径装的是仓库自己的版本,大版本天然一致;模板真盖错了大版本仍然必须失败 —— 那是 template-consistency.test.ts 的职责,这里不放松它。
  • npm run build 之前重盖,所以产物里带的是修正后的区间,后面 Docker 那条路也跟着一致。
  • 找不到 stamp 就 ::error:: 退 1,不静默跳过 —— 模板哪天不再打这个戳,这里要响。

验证

  • 两个 YAML 都能被 YAML parser 正常解析;if: 折叠成单行表达式(续行与首行同缩进,避免 >- 保留换行)。
  • install 步骤的 shell 通过 bash -n
  • 重盖脚本对着真实模板文件 templates/blank/objectstack.config.ts 跑过:^17^16(喂一个 version: 16.4.2 的假 spec 包),并验证了「无 stamp → ::error:: + 退出码 1」这条失败路径。
  • check:nul-bytescheck:doc-authoring 本地通过。

未在真实 GitHub Actions 上端到端跑过第 2 条 —— 它只在 RC 窗口且仓库版本未发布时才进入兜底分支,本 PR 触碰 .github/workflows/scaffold-e2e.yml,会命中该 workflow 的 path filter,由本 PR 的 CI 实跑给出结论。

只动 CI workflow,不涉及运行时和发布产物;changeset 为空 frontmatter(releases nothing)。

🤖 Generated with Claude Code

https://claude.ai/code/session_01BbNVKv6KgPzuQ5p76nMgnf


Generated by Claude Code

Both red checks on #4422 (`chore: version packages (rc)`) are defects in the
gates themselves, and both recur on every Changesets release PR.

Check Changeset was structurally unsatisfiable for the release PR. The gate
counts changesets a PR *adds* (`git diff --diff-filter=A` vs the base) — right
for an ordinary PR, and the fix #3373 landed after a global `find | wc -l`
proved unable to ever go red in RC mode. But the release PR is the *consuming*
side: it applies pending changesets into versions and CHANGELOGs and adds none,
by construction. Nobody labels a bot-authored PR `skip-changeset`, so the
release sat blocked on a check that could only be red. `changeset-release/main`
is now exempt at the job level, pinned to the bot author as well as the branch
name so a hand-pushed branch of that name cannot borrow the exemption.

Scaffold E2E skewed the protocol major against itself during an RC window. The
install step already falls back to `latest` when the repo's version is not yet
published (`@objectstack/cli@^17.0.0-rc.2` -> ETARGET -> retry as `latest`).
That fallback rewrote the generated project's dependencies but not its
manifest, and the template stamps the repo's protocol major
(`engines: { protocol: '^17' }`, written at version time by
sync-template-versions.mjs) while `latest` still pointed at 16.x. The ADR-0087
D1 handshake then correctly refused to boot the artifact — the gate working, on
a skew the step had introduced:

  package 'e2e-app' targets protocol ^17 (engines.protocol) but this runtime is
  protocol 16.0.0

The fallback now re-stamps `engines.protocol` to the major actually installed,
read off node_modules/@objectstack/spec (PROTOCOL_VERSION is kept in lockstep
with that package's own major, asserted by protocol-version.test.ts), and logs
a `::notice` so the run's true protocol is visible rather than silently
rewritten. Confined to the fallback branch: on the normal path the project
installs the repo's own version, the majors agree by construction, and a
template stamping the wrong major must still fail — which is what
template-consistency.test.ts is for. Re-stamping runs before `npm run build`,
so the artifact and the Docker image (already pinned to the resolved CLI
version by the same reasoning) stay in step.

CI configuration only; releases nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BbNVKv6KgPzuQ5p76nMgnf
@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 3, 2026 1:55pm

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd documentation Improvements or additions to documentation tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

发布 PR(changeset-release/main)常红两处 CI:Check Changeset 结构性必失败 + Scaffold E2E 在 RC 窗口协议大版本错配

2 participants