Community生产力与协作github.com

Dependabot 修复

系统性地诊断并修复 Astro 站点上失败的 Dependabot PR。当用户要求执行 `/dependabot-fix <pr-number>` 时使用此技能。

Dependabot 修复 是什么?

该技能用于系统性地修复在 EthicalML/ethical 仓库中失败的 Dependabot PR。它包含六个阶段(A 到 F),从加载 PR 上下文和高层错误调查开始,然后通过子代理引入仓库约定和验证工具文档。其核心是进行深入的根因诊断,设计一个按风险分级的修复方案和手动测试策略,并执行一个合并基础的像素级对比扫描,以捕获 CI 无法检测到的视觉回归。修复方案会直接提交到 Dependabot PR 分支,在检查通过且扫描显示零差异后合并,最后将详细报告作为评论发布。该技能适用于 Claude Code、Cursor、Codex 等支持基于代理的工作流、可以执行 bash 命令和编辑文件的 AI 编码工具。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/EthicalML/ethical/tree/HEAD/.claude/skills/dependabot-fix

Installed? Explore more 生产力与协作 skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Dependabot 修复 是做什么的?

系统性地修复一个失败的 Dependabot PR。用户会提供一个 PR 编号(例如 /dependabot-fix 42)。

此技能包含六个阶段(A 到 F)。在完成阶段 D 之前不要开始编辑代码。在完成阶段 B 之前不要深入查看日志。

开始时就设置好 scratch 空间:

mkdir -p ./tmp && touch ./tmp/null
PR_NUM=<来自用户提示>
REPO=EthicalML/ethical

阶段 A — 上下文

步骤 1 · PR 上下文

获取元数据,并生成一段 PR 的书面摘要(生态系统、分组、大小、是否为安全更新、涉及哪些文件)。不要打开源文件。

gh pr view $PR_NUM --repo $REPO --json title,body,headRefName,labels,files,mergeable,createdAt
gh pr diff $PR_NUM --repo $REPO | head -200

识别:

  • 生态系统:npm | github-actions——该仓库仅有这两种
  • 分组:分组(all, all-security)与单个 npm 主版本(主版本被有意排除在 all 组之外,因此每个主版本单独到达)
  • 大小:更改的文件数量和大约的 LOC 变化;对于 npm,检查 package.json 是否移动,还是仅更改了 package-lock.json
  • 任何更改的依赖是否可能影响渲染输出——这决定了阶段 E(参见步骤 8.5)

步骤 2 · 高层错误调查

列出失败的检查,并从每个失败作业的日志中捕获第一条和最后一条错误行。不要调查它们的含义——仅列举症状。

CI(.github/workflows/ci.yml)恰好有三个必需的作业:lint(ESLint + Prettier)、typecheck(npm run check:ratchet)和 build(演示模式中的生产 Astro 构建,无 FORM_ENDPOINT)。其他任何红色的都不是必需的检查。

gh pr checks $PR_NUM --repo $REPO

# 对于每个失败的检查,从 URL 获取作业 ID 并拉取日志
gh run view --job <JOB_ID> --repo $REPO --log 2>./tmp/null \
  | grep -iE "error|exit code|##\[error\]|FAILED|assert|timed ?out" \
  | head -20 > ./tmp/pr-${PR_NUM}-symptoms.txt

输出应为一个项目符号列表,例如:

  • lint: Prettier check failed: package.json
  • typecheck: astro check reported 3 errors, baseline is 0
  • build: [vite] Rollup failed to resolve import "..."

注意 CI 看不到的内容。 Lint、astro-check ratchet 和成功的构建对页面的外观没有任何说明。这个差距是阶段 E 的工作,并且是该仓库中此技能价值最高的部分。


阶段 B — 通过子代理引入上下文

生成两到三个并行的 explore 子代理,其范围限定为 PR 涉及的内容。事先不要自行阅读这些内容——委托给代理。

步骤 3 · 约定子代理

.github/copilot-instructions.md 是该仓库中规范的代理入口点(根目录的 AGENTS.md 和 CLAUDE.md 是指向它的符号链接)。让子代理读取它并返回:变更工作流、本地检查、提交/PR 约定,以及与涉及路径相关的任何注意事项。当 PR 可能涉及样式或 token ratchet 时,也指向 STYLES.md;当组件 API 可能被涉及,指向 REUSABLE.md。

步骤 4 · 验证工具子代理

让它读取 scripts/verify/README.md 并返回一个简报(约 40 行),内容是关于本地验证工具:verify:dom、verify:shots、verify:parity、verify:typewriter 和 check:ratchet 各自断言什么,主题标志和视口标志如何工作,输出位置,以及 parity 允许列表机制是什么以及不是什么。这个简报就是阶段 E 将执行的依据。

步骤 5 · 代码库子代理

让它为涉及的区域生成一个定向地图:

  • diff 中的哪些包实际上被 src/** 或 scripts/** 导入,以及在哪里被导入(某个未被任何内容导入的 bump 与 astro 的 bump 属于不同的风险类别)
  • 构建和检查命令(npm run build, npm run lint, npm run format:check, npm run check:ratchet)
  • bump 是否涉及构建流水线(astro, vite, @astrojs/*, pagefind, mdx/rehype/remark 插件)还是仅涉及工具链(eslint, prettier, typescript)
  • 对于 github-actions PR:哪些工作流发生变化,以及是否有任何更改影响部署路径(.github/workflows/deploy.yml)而不仅仅是 CI

子代理的简报共同构成阶段 C 的工作上下文。


阶段 C — 深度根因诊断

步骤 6 · 诊断

现在——并且仅现在——结合阶段 B 的全部上下文深入失败的作业日志。对于每个失败的检查,将第一条有意义的错误追溯至:

  1. 来自被 bump 依赖的直接回归(导出的删除、签名更改、更严格的验证、默认值更改)
  2. 传递性工具链问题(依赖需要比 .tool-versions 中固定的版本更新的 Node;postinstall 需要更新的运行时;可选的原生绑定未解析)
  3. 无害的 bump 暴露了预先存在的脆弱性(astro-check 基线、-a### token ratchet 或 STYLES.md 哈希因格式化变动而错误)
  4. 基础设施不稳定(注册表速率限制、取消的作业、npm ci 网络故障)

对于分组的 PR,分别诊断每个失败的检查——失败可能有独立的原因,批次中通常可追溯到不同的包。将发现记录在 ./tmp/pr-${PR_NUM}-diagnosis.md 中。


阶段 D — 修复设计

步骤 6.5 · 范围分类——这是修复,还是 Dependabot 配置问题?

在计划修复之前,检查 PR 是否在可修复的范围内。.github/dependabot.yml 将常规的 npm 次要/补丁更新分批到每个生态系统的单个 all 组中,加上一个 all-security 组,并有意将 npm 主版本从 all 组中排除,因此每个主版本单独到达。这种结构意味着两种不同的失败情况:

一个分组的 PR 在一个包上失败。 这是常见情况,并且在范围内。不要放弃整个批次。找到单个有问题的包,要么为其修复代码,要么固定该包(在 package.json 中缩小范围的条目,或忽略该包和版本的 Dependabot ignore 条目),以便批次的其余部分可以落地。放弃一个除一个错误外全部绿色的批次,会为了一个坏更新而抛弃十多个好更新。

范围拒绝触发器(任何一个就足够了——PR 是一个配置问题,而非修复):

  • 单个分组 PR 包含 ≥ 2 个主版本 bump——在当前 npm 组配置下这应该是不可能的,所以如果发生,配置本身已漂移并且是真正的 bug
  • 一个框架级包(astro、vite、@astrojs/*、typescript、eslint、prettier、preact、pagefind)上的单个主版本,且这是一个真正的迁移——不是修复,而是一个项目
  • 批次大部分是常规的,但失败需要对一个无法被绕过固定的包进行迁移

当触发器被触发时,不要尝试修复且不要自行关闭 PR——保持打开状态供仓库所有者处理。相反:

  1. 如果原因是配置漂移,准备 .github/dependabot.yml 的修正作为单独的 PR(留待仓库所有者审查和合并)。否则,不需要更改配置,建议仅将迁移安排为单独的工作。
  2. 将范围拒绝决定以评论形式发布在 Dependabot PR 上:解释为什么无法一次性修复,链接任何配置 PR,并说明迁移将涉及什么。保持 PR 打开——不要暂停等待决定,不要关闭它。
  3. 跳过阶段 F 的提交流程——没有修复。报告内容会融入该评论中。

安全更新组(all-security)保持捆绑:安全 bump 是时间敏感的且足够罕见,拆分它们得不偿失。仅当有具体的阻塞因素时才拆分。

步骤 7 · 综合计划

编写一个涵盖以下内容的计划;按风险缩放深度:

部分始终如果风险 ≥ 中等
根因✅✅
预期更改的文件✅✅
修复方法(及考虑的替代方案)✅✅
风险评级(低/中/高)✅✅
复现步骤✅✅(必须可执行)
手动测试策略✅✅ 扩展
回滚计划✅
影响范围(渲染输出/部署/URL)✅

风险 ≥ 中等,如果满足以下任何一项:

  • bump 涉及构建流水线(astro、vite、@astrojs/*、MDX/rehype/remark 插件、pagefind)
  • 修复编辑 src/ 下的任何内容而非仅仅是配置或锁定文件
  • bump 可以更改生成的 HTML、CSS 排序、字体加载或水合行为
  • github-actions 更改涉及 deploy.yml(部署失败是实时站点中断,而非红色检查)

任何 npm 主版本默认至少为中等。主版本到达正好是因为它需要单独阅读和测试;以比同等大小的批次更严格的审查对待它。

步骤 8 · 手动测试策略(分层)

根据步骤 7 的风险评级对工作分层:

  • 低(仅工具链)——应用修复,运行最狭窄的相关门控(npm run lint、npm run format:check 或 npm run check:ratchet)。无需复现步骤。
  • 中等(构建流水线或 src/ 编辑)——首先在 PR 分支本地复现失败,以证明回归是真实的(而不是 CI 制品)。然后应用修复,重新运行完整的本地检查:npm run lint && npm run format:check && npm run check:ratchet && npm run build。然后阶段 E。
  • 高(主版本、任何可能更改渲染输出的内容、部署更改)——中等中的所有内容,加上阶段 E 的 parity 扫描是强制性的,加上针对构建的 PR head 运行 npm run verify:dom:all,如果涉及 hero 或 motion token,还要运行 npm run verify:typewriter。

将所有 scratch 输出保留在 ./tmp/ 下(已添加到 gitignore)。在抑制输出时使用 ./tmp/null 作为接收器:

npm run build 2>./tmp/null

阶段 E — 针对合并基础的视觉对比

CI 证明站点仍然可以构建。它不能证明站点看起来仍然相同。依赖 bump 根据定义应该像素无关——如果不是,则某些内容渲染不同,而没有人会看到它。这个阶段是该技能在此仓库中存在的原因。

没有像素基线被提交(scripts/verify/out/ 和 tmp/ 已添加到 gitignore),因此比较必须在运行中生成:捕获合并基础,捕获 PR head,进行比较。

步骤 8.5 · 决定是否运行

每次 PR 扫描大约需要 4-5 分钟(两次构建加上对 37 条路由 × 2 个视口的截图扫描)。仅当更改不可能影响渲染时才跳过它。当满足所有以下条件时可跳过:

  • PR 仅为 github-actions,或仅涉及 .github/**
  • src/、public/、astro.config.mjs 或 package.json 的 dependencies 下的文件未更改
  • diff 仅限于 devDependencies,它们的输出不会到达 dist/(eslint*、prettier、@types/*、typescript,当 ratchet 未更改时)

任何其他情况——任何 astro、vite、@astrojs/*、preact、pagefind、MDX/rehype/remark、字体或 CSS 工具 bump,以及每个 npm 主版本——都必须运行扫描。若有疑问,运行它;五分钟比实时站点上的无声视觉回归更便宜。

在报告中明确说明采取了这个决策的哪个分支以及原因。

步骤 9 · 捕获和比较

Playwright 不是仓库依赖项;该工具从已集成到脚本中的 npx 缓存路径驱动它。使用纯静态服务器服务每个构建。

BASE_SHA=$(git merge-base origin/master HEAD)
mkdir -p ./tmp/parity

# --- 合并基础 ---
git checkout $BASE_SHA
npm ci
npm run build
cp dist/index.html ./tmp/parity/base-index.html    # 我们正在服务的指纹
nohup npx --yes http-server dist -p 4126 --silent < ./tmp/null > ./tmp/parity/base-server.log 2>&1 &
BASE_SERVER=$!
npm run verify:shots:all
kill $BASE_SERVER
cp -R scripts/verify/out ./tmp/parity/base

# --- PR head ---
gh pr checkout $PR_NUM --repo $REPO
npm ci
npm run build
cp dist/index.html ./tmp/parity/head-index.html
nohup npx --yes http-server dist -p 4126 --silent < ./tmp/null > ./tmp/parity/head-server.log 2>&1 &
HEAD_SERVER=$!
npm run verify:shots:all
kill $HEAD_SERVER
cp -R scripts/verify/out ./tmp/parity/head

# --- 对比,按视口 ---
npm run verify:parity -- ./tmp/parity/base/1440 ./tmp/parity/head/1440 > ./tmp/parity/1440.json
npm run verify:parity -- ./tmp/parity/base/420  ./tmp/parity/head/420  > ./tmp/parity/420.json

过时的 dist 陷阱。 在两次构建中重用端口 4126 是产生自信而无意义的绿色的最可能方式:如果旧服务器实际上没有关闭,或者 dist 没有被重建,第二次扫描会拍摄第一次构建的照片,并且 parity 通过,因为你比较了两次相同的构建。每次运行都要防止:

  • 在启动下一个服务器之前确认前一个服务器已关闭(lsof -i :4126 应返回为空)。
  • 比较两个指纹——对于更改了 src/ 或构建流水线依赖的 PR,cmp ./tmp/parity/base-index.html ./tmp/parity/head-index.html 返回 "identical" 是表示不信任该运行的信号,而不是结果。
  • 如果扫描自身的 JSON 报告 compared: 0 或每条路由缺失,则服务器未启动;该运行无效,而不是通过。

verify:shots 将暗色主题输出写入 out/<width>/。如果一个 bump 有可能对亮色主题产生不同影响(CSS 工具、颜色处理、token 发射),使用 --theme light 重复扫描,这将写入 out/light/<width>/,并且不会覆盖暗色树。

步骤 10 · 解释结果

verify-parity 每条路由报告两个数字,两者都很重要

…

[truncated for translation]

相关技能