Prhub

#25586 ci: pr-states no longer overwrites running run state when label is removed

原始 PR 作者 hnyls2002 合并时间 2026-05-18 19:23 文件变更 1 提交数 7 评论 1 代码增减 +65 / -35

执行摘要

修复标签移除时 CI 状态被覆盖

修复 pr-states.yml 中的一个缺陷:标签移除后,PR body 中的 CI 状态块会回退到 'Missing label' 或 'Not enabled',覆盖了实际正在运行的工作流链接。这给开发者带来困惑,无法直观了解 CI 最新状态。PR body 描述:'Bug fix for pr-states.yml: keep the actual workflow run link in the PR body even after the gating label is removed'。

此 PR 值得阅读,特别是对维护 CI 工作流的工程师。它展示了如何使用 GitHub API 以及通过预睡眠和重试处理竞态条件的典型方法。简单但有效。

讨论亮点

PR 没有经过正式的 review 讨论,作者直接合并。Gemini Code Assist 曾尝试生成 review 但未成功。整体实现简洁,主要关注 CI 竞态处理,无重大争议。

实现拆解

  1. 识别标签移除事件:在 pr-states.yml 中通过 context.eventNamecontext.payload.action 判断是否为 pull_request_targetunlabeled 事件,设置 justRemovedLabel 标志。
  2. 引入可配置预等待时间:定义 LABEL_OFF_PRESLEEP_MS(6000ms)和 LABEL_ON_PRESLEEP_MS(3000ms)常量。在标签移除场景中,执行更长的预睡眠,等待工作流索引更新。
  3. 重构查询辅助函数:将原有的 findRunWithRetry 替换为更灵活的 findRun,接受配置对象 { preSleepMs, attempts, delayMs },统一所有查询路径。
  4. 调整主逻辑:根据 hasCIjustRemovedLabel 决定预睡眠时间,然后调用 findRun。如果返回的运行状态为 completed 且无运行,则回退到 'Missing label';否则保留运行链接和图标,避免覆盖。以上所有变更均位于文件 .github/workflows/pr-states.yml
文件 模块 状态 重要度
.github/workflows/pr-states.yml CI 工作流 modified 6.22

关键符号

findRun sleep findRunBySha

关键源码片段

.github/workflows/pr-states.yml infrastructure

唯一变更文件,包含所有修复逻辑:标签移除事件识别、预等待常量、重构查询函数及主逻辑调整。

const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const RETRY_ATTEMPTS = 3;
const RETRY_DELAY_MS = 6000;
const LABEL_ON_PRESLEEP_MS = 3000;
const LABEL_OFF_PRESLEEP_MS = 6000;async function findRun(workflowFile, { preSleepMs = 0, attempts = 1, delayMs = 0 }) {
  // 可选预睡眠,等待 GitHub API 索引更新
  if (preSleepMs > 0) await sleep(preSleepMs);
  for (let i = 0; i < attempts; i++) {
    const run = await findRunBySha(workflowFile);
    if (run) return run;
    if (i < attempts - 1) await sleep(delayMs);
  }
  return null;
}// 主 handler 中关键逻辑
const justRemovedLabel = context.eventName === 'pull_request_target' && context.payload.action === 'unlabeled';
let preSleep = 0;
if (justRemovedLabel) {
  preSleep = LABEL_OFF_PRESLEEP_MS; // 标签移除后,等待 6s
} else if (hasCI) {
  preSleep = LABEL_ON_PRESLEEP_MS; // 有标签时,等待 3s
}
const run = await findRun('pr-test.yml', {
  preSleepMs: preSleep,
  attempts: RETRY_ATTEMPTS,
  delayMs: RETRY_DELAY_MS
});
// 后续:如果 run 存在且正在运行,则保留其链接和图标;
// 否则根据标签存在与否显示对应文本

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

风险较低,变更仅限于 CI 工作流脚本,不涉及生产代码。主要风险是预等待时间(6000ms/3000ms)可能在不同网络延迟下不足,导致偶尔仍会覆盖状态;但重试机制(最多3次,间隔6s)可部分缓解。没有单元测试覆盖,依赖手动验证。如果 GitHub API 延迟极端,可能仍会出现竞态。

直接影响所有使用该仓库 PR 工作流的开发者:标签移除后 PR body 中的 CI 状态将保留最近一次运行的信息,而不是立即显示 'Missing label',提供更准确的可见性。对系统无性能影响。团队未来维护 CI 工作流时可参考本模式。

缺少测试覆盖 竞态条件依赖定时

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论