fix(ci): 两个标签写入 job 不再并发、也不再被标签事件重复触发 (#5649) - #5683
Merged
Conversation
`Check PR Size` 与 `Auto Label` 都用**整集 PUT**(`PUT /issues/{n}/labels`)
写标签,不是新增 POST。源码实测(非文档推断):
- `codelytv/pr-size-labeler@v1.10.4` `src/github.sh:68-91`:GET 读 PR 标签,
grep 掉自己那套 size 家族,追加新 size 标签,然后 `curl -X PUT`。
- `actions/labeler@v7.0.0` `src/labeler.ts:56,111-133` + `src/api/set-labels.ts`:
run 开始时快照 `preexistingLabels`,并入 config 命中项,回读一次实时标签,
再 `client.rest.issues.setLabels` —— 就是 PUT。
两者都没有把写入改成新增的输入项;`sync-labels` 也不是那个开关 —— 它只管
「config 自己拥有的标签在 glob 不再命中时是否删掉」(`labeler.ts:81-83`),
缺省已是 false。本 PR 仍把它显式写出,只为防升级漂移,不是本缺陷的修复。
整集 PUT 只在「别人的写入落在读→PUT 窗口内」时才有破坏性,所以本文件能修的是
**重叠**:
1. 两个写入方不再并发(`auto-label` needs `pr-size`)。原先由同一事件同时拉起、
窗口完全重合:PR #5650 run 31051251795(`opened`)里 `Add size label`
22:03:47->22:03:49、`Label based on changed files` 22:03:47->22:03:49,
labeler 的 PUT 在 22:03:49 发出 `unlabeled size/s` —— 抹掉的是它不管的标签。
2. 两个写入方不再被 `labeled`/`unlabeled` 触发。它们唯一的输入是 diff,标签事件
改不了 diff,这种 run 只能把同一个集合再 PUT 一遍 —— 零新信息,多一次互抹
机会。同 PR run 31051273625(由标签事件拉起):`Auto Label` 重算后没写,
`Check PR Size` 在 22:04:22 又 PUT 了一次。两个事件类型保留在 `on:` 里,
因为 `changeset-check` 确实需要(#5580)。
未被本 PR 关闭、并写进文件注释而非留给下一个读者踩:**工作流之外**的写入方
(`gh pr create` 后几秒挂标签的 agent 或人,正好落在这两个 job 运行期间)
仍可能落进 PUT 窗口被抹 —— #5533 的 `skip-changeset` 豁免只活一秒就是这样丢的
(15:46:44 挂上,15:46:45 被 labeler 的 `{size/m, tests}` PUT 抹掉)。关掉这半
需要写入本身变成新增语义,不是排序问题,任何本文件的配置都替代不了。
`changeset-check` 的实时读与计数逻辑(#5580/#5625)、`allow-major`(#5620)一字未动。
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
This was referenced Aug 6, 2026
os-zhuang
marked this pull request as ready for review
August 6, 2026 00:13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5649
本 PR 只做 issue 的落点 2(CI 侧)。落点 1(客户端写入语义)不改代码,实测结论见下方「工具面备案」。
一、归因:两个 job 都在整集 PUT,
sync-labels不是那个开关按派发要求逐个读 pinned 版本的源码,不接受配置文档推断:
codelytv/pr-size-labeler@v1.10.4src/github.sh:68-91(github::add_label_to_pr)grep -w -v掉自己那套 size 家族 → 追加新 size 标签 →curl -X PUT .../issues/$pr_number/labelsactions/labeler@v7.0.0src/labeler.ts:56,111-133+src/api/set-labels.tspreexistingLabels→ 并入 config 命中项 → 回读一次实时标签(pulls.get,补manualAddedDuringRun)→client.rest.issues.setLabels,即 PUT两者都是整集 PUT,都没有把写入改成新增的输入项。
sync-labels不是那个开关:它只决定「config 自己拥有的标签在 glob 不再命中时是否删掉」(labeler.ts:81-83),对外来标签毫无作用,而且action.yml里缺省已经是false。本 PR 仍然把它显式写出来,理由只有一条 —— 防升级漂移;注释里已经写明它不是本缺陷的修复,免得下一个读者把它当成已修。谁抹的:run/job 级对号(PR #5650)
openedrun31051251795:两个写入步骤的执行窗口完全重合;22:03:49 这条
unlabeled size/s与labeled documentation同秒同 actor,只有 labeler 的一次 PUT{documentation}能同时解释两者 —— 它的快照与回读都早于 22:03:48。方向二的抹除者是Auto Label(actions/labeler)。同一判据套回 #5533 的 15:46:45:
unlabeled skip-changeset+labeled size/m+labeled tests三条同秒,只有 labeler 的一次 PUT{size/m, tests}能同时解释(size-labeler 的写入会保留skip-changeset、也不会加tests)。同一个抹除者。二、改了什么(只动这两个 job 的配置)
整集 PUT 只在「别人的写入落在读→PUT 窗口内」时才有破坏性。本文件能修的是重叠:
auto-label加needs: pr-size。原先由同一事件同时拉起、窗口重合(上表)。串行后 labeler 的快照里已经有 size 标签,PUT 会把它带上。!cancelled()显式写出:needs只用于排序,size job 失败/跳过不该顺手关掉路径打标。labeled/unlabeled触发 —— 它们唯一的输入是 diff,标签事件改不了 diff,这种 run 只能把同一集合再 PUT 一遍:零新信息,多一次互抹机会。现场标本:同 PR 的 run31051273625由标签事件拉起,Auto Label重算后无写入(labeler.ts:111的isEqual短路),Check PR Size在 22:04:22 又 PUT 了一次。两个事件类型保留在on:里,因为changeset-check确实需要(Check Changeset 从事件载荷读skip-changeset标签:开 PR 后 5 秒内加标签,首个 run 永久红(重跑复用载荷)—— 一日三例 #5580)。全仓 grep 确认
size/*、documentation、tests没有任何门禁/脚本消费,只有.github/labeler.yml与本文件提到它们 —— 所以取消「标签事件驱动的自动补挂」不会让任何判据失去输入。⛔ 未触碰:
changeset-check的实时读与计数逻辑(#5580/#5625)、allow-major(#5620)、.github/labeler.yml、MCP 服务端。三、验证
node scripts/check-workflow-status-functions.mjs→OK (scanned 22 workflow file(s), 39 job(s), 21 job-level if: expression(s); 9 read needs.*.outputs.*, all naming a status function);--self-test→ 34 assertions 全过。pr-size无needs、if为两个事件排除;auto-labelneeds=pr-size、if含!cancelled();changeset-check的if与 main 逐字一致;labeler stepwith={repo-token, configuration-path, sync-labels: false}。node scripts/check-nul-bytes.mjs→OK (scanned 5600 tracked text file(s) ...);另按控制字符条款做了闸门盲区自扫grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]',零命中。pull_request事件的 workflow 定义取自 merge ref,所以本 PR 的改动在本 PR 自己的 run 上就生效,A/B 可直接看本 PR 的 timeline。labeler 的配置文件同样取自 merge ref ——src/api/get-content.ts用ref: github.context.sha,pull_request下即 merge commit(本 PR 没改labeler.yml,但派发问到了,一并记为源码结论)。github-actions[bot]不应再出现「针对本 job 不管的标签的unlabeled」;Check PR Size与Auto Label的执行窗口不再重合(后者started_at晚于前者completed_at);标签事件不再拉起这两个 job(对应 run 里它们为skipped)。四、未关闭的一半(留给维护者决策,本 PR 不擅自动依赖)
工作流之外的写入方 —— 例如
gh pr create之后几秒挂skip-changeset的 agent 或人,正好落在这两个 job 运行期间 —— 仍可能落进 PUT 窗口被抹。#5533 的豁免标签只活一秒就是这样丢的(15:46:44 挂上,15:46:45 被 labeler 的 PUT 抹掉),而这正是本 issue 里有实际代价的那一半。它需要写入本身变成新增语义,不是排序问题;两个 action 都没有对应的配置开关,只剩「自己拥有写入路径 / 换 action」这类决策。已按报告契约上报给 PM,注释里也写明了边界,没有伪装成已修。五、工具面备案(落点 1,不改代码)
MCP
issue_write的labels字段语义会在本 PR 上做一次可控实验(挂标签前后回读),结论写进 #5649 的评论。agent 指令面「只加一个标签、不要整集写入」的条款已由 #5559 / PR #5650 落地,本单只补工具面事实。Changeset
workflow-only、无用户可见变更 → 走
skip-changeset标签路线,不写空 frontmatter changeset(#4898 / #5292)。Generated by Claude Code