Skip to content

ci(release): 加发布条件闸(release PR 拿不到 CI,合并前需要机器判据) - #134

Merged
ReSerendipity merged 1 commit into
mainfrom
ci/release-readiness-gate
Sep 22, 2026
Merged

ReSerendipity merged 1 commit into
mainfrom
ci/release-readiness-gate

Conversation

@ReSerendipity

Copy link
Copy Markdown
Owner

为什么要这道闸

这轮量到的机制:release-please 自己开的 PR 一条 CI 检查都没有。
GitHub 固定行为 —— GITHUB_TOKEN 产生的提交不再级联触发 workflow。实测两条都是空数组:

gh pr checks 120   →  0 项          gh pr checks 132   →  0 项

于是我在 #123/#129 里都写过的那句「手工同步位会红在 release PR 上,补一个 commit 即可」不成立
test_all_version_sites_agree 之类的闸只会红在合并之后的 main 上,而那时 RP 已经把 tag 打上、
Release 已经建好、资产已经挂上。红在事后 = 没有拦到任何东西。

改了什么

作用
scripts/check_release_readiness.py(新) 检一棵工作树的发版条件。判据不在这里重写 —— 它 importlib 载入 tests/test_version_consistency.py,把 8 条 test_ 逐条跑一遍,再补两条 CI 看不到的(manifest 与目标版本一致、CHANGELOG.md 里有 ## [新版本] 段)。CI 里红的与发版前拦的同源,不会各漂一半
release-please.yml permissionsstatuses: write;RP 步骤之后加一步:把 release PR 的 head 取成 worktree → 跑脚本 → 结论回写成 commit status release-gate(含指回本次 run 的链接),全文贴进 job 摘要
tests/test_version_consistency.py 修一处我自己写的随机性:安装器那条判据用 next(iter(set(sites.values()))) 取基准,版本位矛盾时是在随机挑一个当真值 —— 这轮用假工作树真撞出来一次"该红却绿"。改成基准取 pyproject.toml

刻意不让这个作业失败:结论已经以 status 打在 PR 上;要真拦合并,是在分支保护里把
release-gate 加成必需检查(一键决定,属于 owner)。让作业红只会把"有一条待发 release PR"
这件事染到每次 main push 的历史上 —— 那不是我们想要的噪声。

验收(拿真对象试过,不是只跑 fixture)

输入 结果
当前 main(2.2.4,全对齐) rc=0,"发版条件满足:全部版本位 = 2.2.4,判据全过"
PR #132 的真 head(RP groom 出的 2.2.5,手工位仍停在 2.2.4) rc=1,点出 4 处版本位落后config.yaml / Cargo.lock / deployment.yaml / setup.nsi)+ version.json 的 changelog 过期 + OutFile 未跟到 v2.2.5

第二行就是"没有这道闸会发生什么"的现场证据:GitHub 会把那条 PR 显示成 MERGEABLE

测试:test_release_readiness_gate.py 4 条 + test_version_consistency.py 8 条 + test_benchmark_gate.py 12 条
= 24 passedruff check / format --check 通过;release-please.ymlyaml.safe_load
pre-push 的 ruff / format / mypy 棘轮(103 不变)全过。

下一步(合完这条之后)

  1. 按 owner 指示合 chore(main): release 2.2.5 #132:先把 5 类手工位在它的分支上补齐,用本条脚本检过再合,
    然后核对 RP 是否真的自动打了 v2.2.5 tag、建了 Release、build-release 挂上资产 ——
    这是 RP 自动路径的第一次完整实跑。
  2. 再单独提一条:给 RP 配置加 exclude-paths,让只改文档的提交不再自动切出 release PR
    (今天 chore(main): release 2.2.5 #132 就是被两条 docs(DOD) 提交顶出来的 2.2.5)。这条没跟本 PR 混在一起,
    因为它改变的是"什么算可发布",需要独立观察一次真 run 才能确认行为。

机制账(这轮量到的):release-please 自己开的 PR **一条 CI 检查都没有**。GitHub 固定行为:
GITHUB_TOKEN 产生的提交不再级联触发 workflow。实测 #120#132 的 `gh pr checks` 都是空数组。
于是"手工同步的 5 类版本位会红在 release PR 上、补一个 commit 即可"这个假设不成立 ——
那些闸只会红在合并之后的 main 上,而那时 tag 与 Release 已经发出去了。

- 新增 scripts/check_release_readiness.py:检一棵工作树的发版条件。**判据不在这里重写** ——
  它 importlib 载入 tests/test_version_consistency.py 把 8 条 test_ 逐条跑一遍,
  再补两条 CI 看不到的(manifest 与目标版本一致、CHANGELOG 里有 ## [新版本] 段)。
  这样"CI 里红的"与"发版前拦的"永远同源,不会各漂一半。
- release-please.yml:permissions 补 statuses: write;新增"发布条件检查"步骤,在 RP 步骤之后跑,
  把 release PR 的 head 取成 worktree 跑脚本,结论回写成 commit status `release-gate`
  (成功/失败 + 指回本次 run),并把全文贴进 job 摘要。
  **刻意不让这个作业失败**:结论已经打在 PR 上,要真拦合并就在分支保护里把 release-gate
  加成必需检查(一键,owner 的决定);让作业红只会把"有一条待发 release PR"染到每次 main push 的历史上。
- 顺手修一处我自己写的随机性:test_installer_artifact_names_track_the_version_site 用
  next(iter(set(sites.values()))) 取基准版本 —— 版本位矛盾时那是**随机挑一个**当真值,
  setup.nsi 可能恰好撞上被挑中的那个而判过(这次用假工作树真撞出来一次)。改成基准取 pyproject。
  同时 tests/test_release_readiness_gate.py 里那条断言现在能稳定点到 OutFile。

验收:
- 脚本对当前 main(2.2.4 全对齐)→ rc=0 "发版条件满足"
- 脚本对 **PR #132 的真 head**(RP groom 出来的 2.2.5,手工位还停在 2.2.4)→ rc=1,
  点出 4 处版本位落后 + changelog 过期 + OutFile 未跟 —— 这就是"没这道闸会发生什么"的现场证据
- tests/test_release_readiness_gate.py 4 条 + test_version_consistency 8 条 + test_benchmark_gate 12 条
  = 24 passed;ruff check / format 通过;release-please.yml 过 yaml.safe_load

Signed-off-by: ReSerendipity <zengyangc@outlook.com>
@ReSerendipity
ReSerendipity merged commit a558fd5 into main Sep 22, 2026
30 checks passed
ReSerendipity added a commit that referenced this pull request Sep 22, 2026
v2.2.5 发完之后核对下游:`gh run list --workflow docker-publish.yml` 上 v2.2.2 / v2.2.3 /
v2.2.4 各有一条 `ev=push br=vX.Y.Z`,**v2.2.5 一条都没有**;`gpg-signed-release.yml` 同理
(三条 `ev=release`,2.2.5 缺席)。原因是同一条 GitHub 固定行为 —— bot 用 `GITHUB_TOKEN`
产生的事件不级联,而 RP 打的 tag 和建的 Release 正是它产的。#128 只写过"release PR 拿不到 CI"
这一面,没写它会连带吃掉 tag/release 两个下游触发,于是本次实测才发现。

后果是具体的:`deploy/kubernetes/deployment.yaml:40,61` 手工同步到了
`ghcr.io/reserendipity/tts-multimodel:2.2.5`,而 ghcr 上今天没有这个标签。两处都不能退回
2.2.4 消红(`test_all_version_sites_agree` 会把版本位一致性判红),所以唯一的自洽修法是补跑
`gh workflow run docker-publish.yml --ref v2.2.5` —— `metadata-action` 的 `type=semver`
在 tag ref 上就能出 `:2.2.5`,工作流不用改。这一步按"Release 侧动作交回 owner"的约定留给所有者点头。

顺带修一处已经过期的话:§1 末尾那段还在说"要把它变成机器闸就得配一个能报 commit status 的作业 ——
那是权限决策,不在现状里",而 #134 已经把它建出来了(报 `release-gate`、不拦截)。

GPG 那一格现在不痛(`GPG_PRIVATE_KEY` 未配 → 作业进 skip 分支只出 notice),但密钥配上之后
RP 发的每个版本都要手工补跑,这条也写进 §1 第 4 条,免得下次又当成"自动路径会替我做"。

验证:`pytest tests/test_version_consistency.py tests/test_release_readiness_gate.py
tests/test_docker_cache_budget.py` → 14 passed(basetemp 换掉才跑起来:
`pytest-of-Doro/pytest-current` 有残留目录导致 WinError 5,与本改动无关)。
`已发布最新 = v2.2.5` 一行未动,第 10 处版本位仍与 9 处代码位一致。

Signed-off-by: ReSerendipity <zengyangc@outlook.com>
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.

1 participant