执行摘要
改进 CI 斜杠命令 emoji 语义并实现结果回写
根据 PR 描述,原回复使用 ✅/❌ 容易被误解为测试通过/失败,需要区分触发状态与测试结果;此外,rerun 完成后用户无法及时获知结果,需要回写机制。目的是改善开发者使用 slash-command 的体验。
值得精读,尤其是幂等设计和并发控制。建议后续类似的 CI 指令可用此模式。
无实质性讨论,仅有一个 bot 确认变更的评论。主要设计决策在 PR body 中已有阐述。
根据 PR 描述,原回复使用 ✅/❌ 容易被误解为测试通过/失败,需要区分触发状态与测试结果;此外,rerun 完成后用户无法及时获知结果,需要回写机制。目的是改善开发者使用 slash-command 的体验。
值得精读,尤其是幂等设计和并发控制。建议后续类似的 CI 指令可用此模式。
无实质性讨论,仅有一个 bot 确认变更的评论。主要设计决策在 PR body 中已有阐述。
替换 emoji:在 slash_command_handler.py 中将触发成功/失败的 emoji 替换为 🚀/⛔,并保持错误提示用 ⛔。
新增结果回写脚本:write_rerun_test_result.py 是独立脚本,通过 GitHub API 获取指定评论,根据 marker(如 <!--rrt:0-->)定位行,替换 ⏳ 为 ✅/❌,并将 marker 改为 :done 实现幂等。若 marker 未找到,则按重试间隔 [0, 5, 15] 秒重试,三次后静默退出,不中断 CI。
修改工作流:rerun-test.yml 新增 reply_comment_id 和 reply_marker 输入;添加 write-back-result job,在 always() 条件下根据测试 job 成功/失败决定状态,调用写入脚本。job 通过 concurrency: rerun-test-writeback-<id> 串行化对同一评论的写回。
修改 handler 触发流程:在 _dispatch_batch 函数中添加 reply_comment_id 和 reply_marker 参数,并传递到 workflow dispatch 的 inputs 中。handler 在触发前先创建一个占位评论,获取 comment id,并为每个 batch 分配唯一的 HTML 注释 marker(例如 <!--rrt:0-->),然后将评论 body 编辑为包含这些 marker 的最终形式。
幂等与容错:写入脚本检测 marker 已存在则跳过;重试策略避免短暂竞争;最终失败不影响主流程(返回 0)。
| 文件 | 模块 | 状态 | 重要度 |
|---|---|---|---|
scripts/ci/utils/write_rerun_test_result.py |
CI 脚本 | added | 5.79 |
scripts/ci/utils/slash_command_handler.py |
CI 脚本 | modified | 4.97 |
.github/workflows/rerun-test.yml |
工作流 | modified | 4.09 |
scripts/ci/utils/write_rerun_test_result.py
infrastructure
核心新增文件,实现评论内容更新逻辑,包括 marker 查找、替换、重试和幂等退出。
import argparse, os, sys, time, requests
RETRY_DELAYS_SEC = [0, 5, 15]
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--comment-id", required=True, type=int)
ap.add_argument("--marker", required=True, help="e.g. <!--rrt:0-->")
ap.add_argument("--status", required=True, choices=["success", "failure"])
ap.add_argument("--repo", required=True, help="owner/repo")
args = ap.parse_args()
token = os.environ.get("GITHUB_TOKEN")
if not token:
return 1
icon = "✅" if args.status == "success" else "❌"
done_marker = args.marker.replace("-->", ":done-->")
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28"
}
url = f"https://api.github.com/repos/{args.repo}/issues/comments/{args.comment_id}"
# 重试逻辑:最多 3 次,间隔逐步增加
body = None
for attempt, delay in enumerate(RETRY_DELAYS_SEC):
if delay:
time.sleep(delay)
resp = requests.get(url, headers=headers, timeout=15)
if resp.status_code != 200:
return 1
body = resp.json().get("body") or ""
if done_marker in body:
# marker 已被改写,说明已成功回写,幂等跳过
return 0
if args.marker in body:
break
print(f"Marker {args.marker} not found (attempt {attempt + 1}); will retry.")
else:
# 三次重试后仍未找到 marker,静默退出,不将失败传播到 CI 流程
print(f"WARNING: marker {args.marker} not found after retries; skipping writeback.")
return 0
# 逐行替换:找到含 marker 的行,替换 ⏳ 为结果图标,改写 marker 为 done_marker
new_lines = []
for line in body.splitlines(keepends=True):
if args.marker in line:
line = line.replace("⏳", icon, 1)
line = line.replace(args.marker, done_marker)
new_lines.append(line)
new_body = "".join(new_lines)
# 通过 PATCH 更新评论 body
update_resp = requests.patch(url, headers=headers, json={"body": new_body}, timeout=15)
if update_resp.status_code not in (200, 201):
print(f"ERROR: PATCH failed: {update_resp.status_code} {update_resp.text}")
return 1
return 0
当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。
写回操作依赖 GitHub API,若 token 不足或网络问题可能导致失败,但脚本重试并返回 0 避免 CI 失败;并发控制依赖于 job-level concurrency,在极端情况下多个同时写回可能冲突,但由于按行替换且 marker 不同,冲突概率低;另外如果 handler 在创建占位评论后失败,占位评论残留,但不会造成功能问题。
影响所有使用 /rerun-test 的 PR,提升可见性和确定性;对用户是正向体验提升;对系统没有性能影响。
当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。
参与讨论