Dependabot 修復 是做什麼的?
系統性地修復失敗的 Dependabot PR。使用者提供 PR 編號(例如 /dependabot-fix 42)。
此技能分為 六個階段 (A–F)。在完成階段 D 之前 不要 開始編輯程式碼。在完成階段 B 之前 不要 深入研究日誌。
一開始設定一次暫存空間:
mkdir -p ./tmp && touch ./tmp/null
PR_NUM=<from user prompt>
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)vs 單一的 npm major(major 版本被設計排除在all群組之外,因此每個 major 會單獨到達) - 大小:更改的檔案數量和近似 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.jsontypecheck:astro check reported 3 errors, baseline is 0build:[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 各自斷言什麼、主題標誌和 viewport 標誌如何運作、輸出落在哪裡、以及 parity 允許列表機制的用途和限制。此簡報是階段 E 執行所依據的內容。
步驟 5 · 程式碼庫子代理
要求它為觸及的區域產生一個有針對性的地圖:
- 差異中的哪個(些)套件實際上被
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-actionsPR:哪些工作流程發生變更,以及任何變更是否影響部署路徑(.github/workflows/deploy.yml)而不僅僅是 CI
子代理的簡報共同構成階段 C 的工作上下文。
階段 C — 深度根因診斷
步驟 6 · 診斷
現在 — 並且只有在現在 — 在具備階段 B 完整上下文的情況下,深入研究失敗任務的日誌。對於每個失敗的檢查,將第一個有意義的錯誤追溯到:
- 來自 bumped 依賴項的直接回歸(已移除的匯出、簽名變更、更嚴格的驗證、變更的預設值)
- 傳遞性的工具鏈問題(依賴項需要比
.tool-versions固定的更新的 Node;postinstall 需要更新的執行環境;可選的原生綁定無法解析) - 由無害的 bump 暴露的既有脆弱性(astro-check baseline、
-a###token ratchet、或STYLES.md雜湊因格式變動而觸發) - 基礎設施波動(註冊表速率限制、取消的任務、
npm ci網路故障)
對於一個分組的 PR,分別 診斷每個失敗的檢查 — 失敗可能具有獨立的原因,並且批次中它們通常可以追溯到不同的套件。將發現記錄在 ./tmp/pr-${PR_NUM}-diagnosis.md 中。
階段 D — 修復設計
步驟 6.5 · 範圍分類 — 這是修復,還是 Dependabot 配置問題?
在計劃修復之前,檢查 PR 是否完全 在範圍內 可以修復。.github/dependabot.yml 將常規的 npm minor/patch 更新批次處理為每個生態系統一個 all 群組加上一個 all-security 群組,並刻意將 npm majors 從 all 群組中排除,以便每個 major 單獨到達。這種形狀意味著兩種不同的失敗情況:
一個分組的 PR 在一個套件上失敗。 這是常見情況,並且 在範圍內。不要放棄整個批次。找到單一的問題套件,並為其修復程式碼,或固定該單一套件(package.json 中的條目縮小範圍,或該套件和版本的 Dependabot ignore 條目),以便其餘的批次可以合併。放棄一個除了問題套件外皆為綠色的批次會因為一個壞的更新而丟棄十幾個好的更新。
範圍拒絕觸發條件(任何一個都足夠 — 該 PR 是配置問題,而不是修復):
- 一個單一的群組 PR 包含 ≥ 2 個 major bump — 這在當前的 npm 群組配置下應該是不可能的,所以如果發生,配置本身已經偏離並且是實際的 bug
- 一個在框架層級套件(
astro、vite、@astrojs/*、typescript、eslint、prettier、preact、pagefind)上的孤立 major,這是一個真正的遷移 — 不是一個修復,而是一個專案 - 批次大部分是常規的,但其失敗需要在一個無法固定跳過的套件上進行遷移
當觸發時,不要嘗試修復 並且 不要自己關閉 PR — 將其保持開啟給擁有者。而是:
- 如果原因是配置偏離,則準備
.github/dependabot.yml的更正作為一個單獨的小 PR(留待擁有者審查和合併)。否則,不需要配置變更,建議僅是將遷移安排為其自己的獨立工作。 - 在 Dependabot PR 上以評論形式說明範圍拒絕決定:解釋為什麼無法一次性修復,連結任何配置 PR,並說明遷移將涉及什麼。保持 PR 開啟 — 不要暫停等待決定,不要關閉它。
- 跳過階段 F 的提交流程 — 沒有修復。報告內容則合併到該評論中。
安全性更新群組(all-security)保持捆綁:安全性 bump 是時間敏感且足夠罕見,以至於拆分它們的成本超過了節省。僅在具體的阻礙因素迫使時才拆分一個。
步驟 7 · 全面計劃
撰寫一個涵蓋以下內容的計劃;根據風險調整深度:
| 章節 | 始終 | 如果風險 ≥ 中等 |
|---|---|---|
| 根因 | ✅ | ✅ |
| 預期更改的檔案 | ✅ | ✅ |
| 修復方法(以及考慮過的替代方案) | ✅ | ✅ |
| 風險評級(低/中/高) | ✅ | ✅ |
| 重現步驟 | ✅ | ✅ (必須可執行) |
| 手動測試策略 | ✅ | ✅ 已擴充 |
| 回滾計劃 | ✅ | |
| 影響範圍(渲染輸出 / 部署 / URL) | ✅ |
風險 ≥ 中等如果 任何 以下條件成立:
- bump 觸及建置管道(
astro、vite、@astrojs/*、MDX/rehype/remark 插件、pagefind) - 修復編輯了
src/下的任何內容,而不僅僅是配置或鎖定檔 - bump 可以改變發出的 HTML、CSS 順序、字體載入或 hydration 行為
github-actions變更觸及deploy.yml(失敗的部署是即時網站中斷,而不是紅色檢查)
任何 npm major 預設至少為中等。一個 major 單獨到來正是因為它需要被單獨閱讀和測試;以比相同大小的批次更高的審查級別對待它。
步驟 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。 - 高(major 版本、任何可能改變渲染輸出的內容、部署變更) — 中等項目中的所有內容,加上階段 E 的 parity 比對是 強制的,加上對建置後的 PR head 執行
npm run verify:dom:all,如果英雄區或 motion token 受到影響,再加上npm run verify:typewriter。
將所有暫存輸出保留在 ./tmp/(已被 gitignore)。在抑制輸出時使用 ./tmp/null 作為接收器:
npm run build 2>./tmp/null
階段 E — 針對合併基準的視覺一致性
CI 證明網站仍然能建置。它並不證明網站看起來仍然一樣。依賴項 bump 根據定義應該是像素中性的 — 如果不是,則表示某些內容被不同地渲染,而沒有人會注意到。這個階段是此技能在此儲存庫上存在的原因。
沒有提交像素基準線(scripts/verify/out/ 和 tmp/ 已被 gitignore),因此必須在運行中產生比較:擷取合併基準,擷取 PR head,進行比較。
步驟 8.5 · 決定是否執行
比對大約花費 4–5 分鐘 每個 PR(兩次建置加上對 37 條路徑 × 2 個 viewport 的兩次螢幕截圖比對)。僅當變更 不可能 影響渲染時才跳過它。當 所有 以下條件成立時可以跳過:
- PR 僅是
github-actions,或僅觸及.github/** src/、public/、astro.config.mjs或package.jsondependencies下的檔案沒有更改- 差異僅限於其輸出永遠不會到達
dist/的 devDependencies(eslint*、prettier、@types/*、當 ratchet 未變更時的typescript)
任何其他情況 — 任何 astro、vite、@astrojs/*、preact、pagefind、MDX/rehype/remark、字體或 CSS 工具 bump,以及每個 npm major — 都執行比對。如有疑問,請執行它;五分鐘比在即時網站上發生無聲的視覺回歸要便宜。
在報告中明確說明採用了哪個決定分支以及原因。
步驟 9 · 擷取和比較
Playwright 不是 儲存庫的依賴項;該工具從已接入腳本的 npx 快取路徑驅動它。使用純靜態伺服器服務每個建置。
BASE_SHA=$(git merge-base origin/master HEAD)
mkdir -p ./tmp/parity
# --- merge base ---
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
# --- 比較,按 viewport ---
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 每條路由報告兩個數字,兩者都很重要
…