news 2026/9/15 22:04:16

基于 OpenSRE 的 GitHub CI 健康巡检 Skill:用只读报告守护每一条失败检查

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于 OpenSRE 的 GitHub CI 健康巡检 Skill:用只读报告守护每一条失败检查

基于 OpenSRE 的 GitHub CI 健康巡检 Skill:用只读报告守护每一条失败检查

【免费下载链接】opensreBuild your own AI SRE agents. The open source toolkit for the AI era.项目地址: https://gitcode.com/GitHub_Trending/op/opensre

导读

reporting-github-ci-failures是 OpenSRE 内置的 Skill(技能),用于对恰好一个GitHub 仓库生成"此时此刻正在失败的 CI 检查"健康报告,可精确收窄到某个分支或某个 Pull Request,并通过调度器周期性投递到指定目的地。本文以该 Skill 的定义文档为主线,结合 ci_health_runner.py 的底层实现与调度契约源码,完整讲解它的适用边界、运行机制、只读约束、调度配置与输出格式,帮助你直接用它搭建仓库级 CI 健康巡检,或在自己的场景中复刻同类能力。读完你将掌握:如何理解并配置该 Skill、它内部究竟拉取哪些 GitHub 数据、为何它被设计为"调度器预取 + Agent 忠实转述",以及它与性能分析、CI 修复两个相邻 Skill 的职责划分。

一、Skill 定位:现在正在失败,而非历史趋势

1.1 一句话定义

根据 SKILL.md 的 front-matter 描述,该 Skill 的作用是:

一个仓库(可选收窄到某个分支或 PR)生成当前正在失败的 GitHub CI 检查的只读健康报告。

不是用于 CI/CD 性能、可靠性 KPI、失败率或一段时间内的宕机分析——那些属于analyzing-github-ci-performance(30 天窗口的指标分析)。二者的边界在 Skill 定义中写得很清楚:

  • 问"现在哪些检查失败" →reporting-github-ci-failures
  • 问"过去 30 天CI 表现如何、失败率多高、开发者等待多久" →analyzing-github-ci-performance

1.2 元数据与使用场景

Skill 头部声明(front matter)本身即是对使用边界的机器可读定义:

name: reporting-github-ci-failures metadata: owner: Ceren last_changed_by: Jan last_changed_at: 2026-09-12 usecases: - For maintainers checking which CI checks are failing now in one repository, branch, or PR. - For teams receiving recurring CI failure reports at a chosen destination. requires: - GitHub authentication with read access to the target repository. - Explicit repository owner and name for scheduled execution. - For recurring delivery, a configured scheduler and destination. version: '1.1' recurring: true

注意最后一行recurring: true:这是该 Skill 可以无人值守周期性运行的关键标记,调度器正是依据它来决定能否把任务"钉住"并反复执行(详见第五节)。

典型应用场景有两个:

  1. 维护者自查:想知道某个仓库、分支或 PR 现在挂了哪些检查;
  2. 周期性投递:团队希望在一个固定目的地(如 Slack、邮件等)周期性地收到 CI 失败清单,由调度器自动产出并送达。

1.3 范围硬约束:一个仓库,分支与 PR 二选一

文档对输入范围做出了严格规定:

  • 调度器必须提供ownerrepo
  • 可选提供branchpr_number二者永不共存

这一约束在实现层被强制校验。查看 ci_health_runner.py 的run_github_ci_health

owner = _required_text(payload, "owner") repo = _required_text(payload, "repo") branch = str(payload.get("branch") or "").strip() raw_pr = str(payload.get("pr_number") or "").strip() if branch and raw_pr: raise RuntimeError("GitHub CI health accepts either branch or pr_number, not both.")
  • owner/repo缺失会直接抛出RuntimeError_required_text保证空值不可接受);
  • branchpr_number同时给出会报错;
  • pr_number必须是正整数,否则同样报错。

也就是说,一次运行有且仅有三种作用域之一:单条 PR单个分支整个仓库(默认分支 + 打开的 PR 们)。

二、运行模型:预取即真相,Agent 只做忠实转述

2.1 数据不是 Skill 自己拉取的

这是本 Skill 最重要的设计点:在无人值守执行期间,Skill 本身不发起任何 GitHub 工具调用。真正的数据采集发生在 Skill 运行之前——由调度器调用run_github_ci_health,通过只读的 GitHub REST GET 请求收集目标仓库的 CI 数据,并把完整渲染好的报告块注入给 Agent。

因此 Skill 文档对 Agent 的要求是:

  • 把预取到的 CI health 块当作完整的真相来源,原样返回为最终报告;
  • 不要去发现更广的组织或仓库范围;
  • 保留块中的每一条失败检查、链接、时间、责任 PR/分支、覆盖率提示与修复交接信息。

2.2 工具清单与边界

工具用途何时允许
run_github_ci_health调度器预取 CI 健康数据(只读 GET)每次调度运行前,由调度器调用
propose_scheduled_delivery配置周期性报告投递仅交互式配置阶段,绝不在无人值守运行中调用
summarize_github_pr_status交互式展示当前失败的检查仅在交互式会话中使用(实现见 work_status.py 中的summarize_github_pr_status
scan_local_git_workspace/ask_user_choice交互式发现仓库并让用户选择仅交互式,当请求未指明仓库时
fix_github_pr_cigithub_clishell_runcli_exec修复/外部命令/集成状态打印禁止——无人值守期间绝不调用任何变更性工具

文档特别强调:交互式发现仓库时,禁止通过cli_execopensre healthopensre integrations …)、shell_rungithub_cli去探测仓库、token 或环境,因为它们打印的是无关的集成状态,不属于本 Skill 的职责。

2.3 只读铁律与修复交接

该工作流是只读的。无人值守期间禁止调用fix_github_pr_cigithub_clishell_run或任何其他变更性/外部命令工具。修复必须由用户交互式发起并明确批准

实现层在报告末尾自动追加了一条固定交接语(_REPAIR_HANDOFF):

Repair handoff: ask OpenSRE to fix the affected PR or branch interactively. The fix_github_pr_ci action requires your approval and is never run by this schedule.

这正是"报告与修复分离"的体现:报告是自动化的、只读的、可无人值守的;修复始终需要人在环(human-in-the-loop)。实际的修复流程由相邻 Skill fixing-github-ci 承担,它要求 GitHub写权限并调用fix_github_pr_ci(含 PR 修复推送、冲突处理、分支修复专用 worktree 等),与本文 Skill 的只读定位完全相反。

三、底层实现:run_github_ci_health的完整数据流水线

数据采集全部位于 integrations/github/ci_health_runner.py,由GitHubRestClient以纯 GET 请求完成。下面按执行顺序拆解其逻辑。

3.1 输入解析与校验

def run_github_ci_health(payload, *, client=None, now=None) -> str: owner = _required_text(payload, "owner") repo = _required_text(payload, "repo") # branch XOR pr_number,pr_number 必须为正整数

返回的是字符串(渲染后的报告),而不是结构化对象——调度器拿到后直接作为 Skill 上下文注入。checked_at默认取当前 UTC 时间,用于计算每条失败的时间年龄。

3.2 三种作用域的分派

if pr_number is not None: failures = _single_pull_request_report(...) # scope = f"PR #{pr_number}" elif branch: failures = _branch_report(...) # scope = f"branch {branch}" else: failures = _repository_report(...) # scope = "default branch and open PRs"
  • PR 作用域:GET/repos/{owner}/{repo}/pulls/{pr_number}取 PR 元数据,读取其head.shahead.ref,责任方标记为PR #{number} ({branch})
  • 分支作用域:GET/repos/{owner}/{repo}/branches/{branch}取分支头 SHA,责任方标记为branch {branch}
  • 仓库作用域:先取仓库元数据拿到default_branch,对默认分支生成报告;再分页拉取state=open的 PR(per_page=100,最多 2 页),对每个打开的 PR 生成报告。超过 100 条打开 PR 时追加覆盖率提示Coverage notice: report limited to the first 100 open PRs.

3.3 针对单个 SHA 的双通道采集

无论哪种作用域,最终都收敛到对某个 SHA 调用_failures_for_sha,它同时拉取两类CI 结果:

  1. Check Runs(GitHub Actions / 第三方 check):GET /commits/{sha}/check-runs?filter=latest&per_page=100,分页采集(最多检测 11 页以发现截断);当检查数超过MAX_CHECK_RUNS_PER_SHA = 1000时截断并追加覆盖率提示;
  2. Combined Commit Status(传统 Status API):GET /commits/{sha}/status

失败判定使用两个冻结集合:

_FAILED_CHECK_CONCLUSIONS = frozenset( {"action_required", "cancelled", "failure", "startup_failure", "timed_out"} ) _FAILED_STATUS_STATES = frozenset({"error", "failure"})

即 Check Run 的conclusion命中上述 5 种即视为失败;传统状态的stateerrorfailure即视为失败。注意cancelledtimed_out也被计入"失败",因此报告反映的是"需要关注"的检查,而不只是字面意义上的 failed。

3.4 单条失败记录的格式化

每条失败记录最终被渲染成一行:

f"- {failure.name} — {failure.url} — {_age(failure.timestamp, now=now)} — {responsible}"
  • name:Check Run 名或 Status context,缺失时回退为Unnamed check/Unnamed status
  • urlhtml_urltarget_url,缺失时回退为link unavailable
  • _age():把completed_at/started_at(或 status 的updated_at/created_at)解析为人类可读的年龄——Xm old(<1 小时)、Xh old(<1 天)、Xd old,无法解析时回退为age unknown
  • responsible:责任 PR(含分支)或责任分支。

3.5 报告整体结构

最终输出是一个多行字符串,结构为:

GitHub CI health — {owner}/{repo} — {scope} [coverage_notices...] # 如有截断提示 - {check} — {url} — {age} — {responsible} # 每行一条失败 ... (空行) Repair handoff: ask OpenSRE to fix the affected PR or branch interactively. ...

若无任何失败,则输出No failing checks found.;若发生GitHubApiError,会包装为RuntimeError(f"GitHub CI health read failed for {owner}/{repo}: {exc}")上抛给调度器。报告头部包含时间基准(checked_at),方便读者判断数据新鲜度。

四、交互式使用:发现仓库、确认范围、提供报告

虽然报告的正式产出由调度器完成,但该 Skill 也定义了完整的交互式路径:

4.1 仓库发现

当用户请求没有指明仓库时,Agent 应:

  1. 调用scan_local_git_workspace扫描本机 Git 工作区;
  2. ask_user_choice让用户从候选中选择;
  3. 严禁用cli_exec/shell_run/github_cli去"探测"仓库与 token。

4.2 交互式展示

在交互式会话中展示"当前失败的检查"时,使用summarize_github_pr_status(见 work_status.py);本 Skill 自己的正式报告由调度器产出。

4.3 把报告升级为周期任务

当用户希望把该报告作为周期性任务时,Agent 应调用propose_scheduled_delivery,并传入:

  • kind = "recurring_skill"
  • skill name = "reporting-github-ci-failures"
  • 精确的ownerrepo
  • 至多一个branchpr_number

这样确认流程能完整保留仓库作用域,避免确认时把范围扩大或换到别的仓库。

五、调度契约:recurring: true背后的机制

该 Skill 的 front-matter 声明了recurring: true,调度器侧有对应的契约实现,位于 core/agent_harness/prompts/skills/scheduling/recurring.py:

  • is_recurring_skill(name):查询 Skill 目录,只有显式标记recurring的 Skill 才允许无人值守调度;
  • pin_recurring_skill(name):返回(skill_name, revision),其中 revision 是 Skill 正文的 SHA-256 哈希(skill_revision),用于把"当前这一版配方"钉住;
  • resolve_scheduled_skill(name, pinned_revision):每次调度 tick 重新加载 Skill 正文并计算哈希,与钉住的 revision 比对;一旦发现revision 漂移(Skill 内容被修改),立即报错并要求"先移除再重新添加调度以接受新配方";
  • validate_skill_inputs(raw):调度输入必须是纯字符串键值对,空键或非字符串值会被拒绝。

这意味着:reporting-github-ci-failures作为周期任务被钉住后,其owner/repo/branch/pr_number输入、以及 Skill 正文本身,都被版本化约束——既防止输入类型混乱,也防止 Skill 在无人值守期间被悄然改动。

六、Skill 家族分工:报告、性能、修复、投递

该 Skill 不是孤立存在的,它与onboarding-github-ci家族内的相邻 Skill 构成完整的 CI 生命周期:

Skill问题域读写性关键工具
reporting-github-ci-failures(本文)此刻哪些检查失败(单仓库/分支/PR)只读run_github_ci_healthpropose_scheduled_delivery
analyzing-github-ci-performance过去 30 天 CI 性能、失败率、等待时间只读analyze_github_ci_reliability
fixing-github-ci修复失败的 PR/分支检查并推送(需批准)fix_github_pr_ci
scheduling-github-ci-fixes把上述能力编排为本地循环调度skill_view加载
connecting-slack把报告投递到 Slack 等目的地配置propose_scheduled_delivery之类

从编排角度看,交互式流程常是这样一条链:先scan_local_git_workspace+ask_user_choice选仓库 →analyze_github_ci_reliability出 30 天指标(性能 Skill)→ 用ask_user_choice提供"调度本地循环 / Slack 接入 / 完成"三选一菜单;而本文的 Skill 则专门负责周期性、只读、即时的失败巡检。值得注意:性能分析 Skill 明确声明"对于当前失败的检查,使用reporting-github-ci-failures",两个 Skill 互为指针、职责互补。

七、把它用起来:一条可落地的配置路径

综合以上机制,要在 OpenSRE 中启用"仓库级 CI 失败周期报告",实际路径大致如下(具体入口以 docs/configuration 与调度文档为准):

  1. 确保认证:GitHub 认证需具备目标仓库的读权限(Skill 的requires声明),可通过opensre integrations setup github完成——这正是性能分析 Skill 在 token 缺失时提示的命令;
  2. 触发交互式流程:向 Agent 提出类似"每天给我owner/repo的 CI 失败报告"的请求;若未指明仓库,Agent 会先scan_local_git_workspaceask_user_choice
  3. 确认调度参数:确认时传入kind=recurring_skill、skill 名reporting-github-ci-failures、精确owner/repo,以及至多一个branchpr_number(注意:分支与 PR 不能同时提供);
  4. 选择投递目的地:通过调度器与投递配置(如 Slack)绑定目的地,此后每次 tick:调度器调用run_github_ci_health预取数据 →resolve_scheduled_skill校验 revision → Agent 忠实转述报告块;
  5. 如需修复:查看报告中的Repair handoff提示,交互式请求fix_github_pr_ci并批准——自动调度永远不触发修复。

配置时的关键校验点可参考实现:owner/repo必填;pr_number必须是正整数;branchpr_number互斥;输入键值必须是字符串。任何违反都会在调度阶段即被RuntimeError拦下,而不是在运行时静默出错。

八、小结

reporting-github-ci-failures是一个把"仓库 CI 健康巡检"做成只读、可调度、范围受限的标准 Skill:

  • 范围上:一次只服务一个仓库,branch/pr_number二选一,杜绝范围蔓延;
  • 数据上:由调度器通过run_github_ci_health预取(Check Runsfilter=latest+ Combined Status 双通道),Agent 只做忠实转述,避免无人值守时失控探索;
  • 安全上:严格只读,修复永远留给交互式 + 显式批准;revision 钉住机制防止 Skill 内容在调度期间被悄然修改;
  • 边界上:与 30 天性能分析(analyzing-github-ci-performance)、CI 修复(fixing-github-ci)清晰分工,报告发现问题、人在环批准修复,形成闭环。

若你要在自己的 OpenSRE 实例上做"CI 失败日报",从本文第一节的元数据约束、第三节的采集逻辑,到第五节的调度契约,已经可以完整还原该 Skill 的运行全貌;更进一步,SKILL_TEMPLATE.md 展示了这类 Skill 的统一撰写骨架(front matter + Plan + Workflow + 完成条件),可作为你设计自有周期性只读巡检 Skill 的模板参照。

【免费下载链接】opensreBuild your own AI SRE agents. The open source toolkit for the AI era.项目地址: https://gitcode.com/GitHub_Trending/op/opensre

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 22:03:41

SpringBoot+Vue+MySQL汽车销售系统全栈实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 22:02:55

深入解析 Scalar useColorMode Hook:Vue 应用中的暗色/亮色模式状态管理

深入解析 Scalar useColorMode Hook&#xff1a;Vue 应用中的暗色/亮色模式状态管理 【免费下载链接】scalar Scalar is an open-source API platform:                                       &#x1f310; Modern REST API Client …

作者头像 李华
网站建设 2026/9/15 22:01:32

汕头建站模板搭建避坑指南:3种方案对比

汕头建站模板搭建避坑指南:3种方案对比 别再被那些一眼假、加载慢、还容易出bug的模板网站坑了。很多汕头老板花了几千块买模板,结果上线三个月,客户问为什么网站打不开,SEO排名还掉到首页外。…

作者头像 李华