/ci-audit — 找出並修復浪費的 GitHub Actions 時間
先測量,再修復少數真正重要的問題。在實際審計中,最大的收穫往往不是慢速的測試套件,而是一個每天失敗數月的排程管線、一個每月計費 730 分鐘的 30 秒每小時 cron,或是一個 SDK 在靜默中重試死請求三次。
此技能資料夾中的 stdlib 腳本 scripts/ci_audit.py 負責測量。您讀取其輸出,決定哪些值得修復,然後推送出去。
python3 <skill-dir>/scripts/ci_audit.py inventory <owner> # 哪些儲存庫執行了 Actions,私有 vs 公開
python3 <skill-dir>/scripts/ci_audit.py month <owner/repo> # 按工作流程計算 30 天內的計費分鐘數
python3 <skill-dir>/scripts/ci_audit.py jobs <owner/repo> --runs 150 # 每個工作的佇列 / 設定 / 執行時間
python3 <skill-dir>/scripts/ci_audit.py steps <owner/repo> <run-id> # 單次執行中每個步驟的秒數
python3 <skill-dir>/scripts/ci_audit.py schedules <owner/repo> # 每個 cron 的每月執行次數
它需要已登入的 GitHub CLI (gh)。month 和 jobs 每次執行會呼叫一次 API,因此活躍的儲存庫需要一兩分鐘。請在背景執行它們。
步驟 0 — 範圍與規則
在測量之前,先與使用者協商:
- 哪些擁有者與儲存庫。 單一儲存庫,或過去 60 天內推送過的所有儲存庫。
- 禁止修改的儲存庫。 其他團隊成員(或其他代理)正在該處進行功能開發。這些儲存庫只會收到附有數據的 Issue,絕不推送分支。
- 合併目標。 預設為整合分支(例如
development)。發佈到預設分支是另一個獨立的是/否決定,但 cron 和排程修復只會在合併後(步驟 6)生效。 - 超出範圍的事項: 減少測試覆蓋率、使用付費執行器、更換 CI 供應商。建議用數據說明這些選項,但不要實作。
現在請閱讀 references/gotchas.md(注意事項參考文件)。
步驟 1 — 盤點與成本
- 對每個擁有者執行
ci_audit.py inventory <owner>。注意私有與公開的區別:只有私有儲存庫會產生費用,但當代理被 CI 阻塞時,每個儲存庫的等待時間都很重要。 - 對於組織,取得實際帳單:
gh api "/organizations/<org>/settings/billing/usage?year=YYYY&month=M"。對於個人帳戶,對每個私有儲存庫使用ci_audit.py month,並將總和與方案中包含的分鐘數進行比較。 - 列出計費分鐘數最多的前 5 個儲存庫。這就是時間花費的地方。
步驟 2 — 先修壞的,再修慢的
對於每個包含排程工作流程的儲存庫:
- 檢查每個工作流程最近 10 次排程執行。任何每次都失敗的工作流程,無論其成本如何,都是首要發現。閱讀其日誌(
gh api repos/O/R/actions/runs/<id>/logs > logs.zip)。 - 對
.github/workflows/執行actionlint。GitHub 無法解析的檔案永遠不會執行其排程。
預期會出現層層錯誤。請參閱 references/fixes.md(修復參考文件)第 1 節。
步驟 3 — 排程
對每個包含 cron 的儲存庫執行 ci_audit.py schedules <repo>。將每月執行次數乘以每次執行的計費分鐘數(來自 jobs)。標記以下情況:
- 排程緊湊的短任務(每小時執行 30 秒的檢查 = 每月 730 計費分鐘)。
- 多個 cron 在同一分鐘執行,並命中同一個有速率限制的 API。
- 每月 cron 導致一次龐大的執行。將工作分散到多個夜晚。
步驟 4 — 逐一工作分析
對於排名靠前的儲存庫:執行 ci_audit.py jobs <repo> --runs 150,然後對每個昂貴工作的一次近期成功執行執行 steps。將每個工作的時間分類:
| 類別 | 指向的問題 |
|---|---|
| 佇列時間高 | 執行器競爭或並發群組。通常不易廉價修復;記錄即可。 |
| 設定時間高 | 相依性安裝與快取(references/fixes.md 第 3–4 節)。 |
| 執行時間高,應用程式測試 | 實際測試時間。除非某個步驟明顯冗餘,否則留著。 |
| 執行時間高,資料管線 | 對階段進行檢測並修復程式碼,而非 CI(references/fixes.md 第 6 節)。 |
| 失敗率 > 5% | 不穩定的測試或損壞的管線(references/fixes.md 第 1、7 節)。 |
步驟 5 — 報告與挑選
按照每月預估節省分鐘數排序,建立一個表格:
| 儲存庫 | 發現 | 證據 | 修復方案 | 每月預估節省 | 風險 |
|---|
包含您不會修復的發現(禁止修改的儲存庫、擁有者的決定,例如 cron 頻率或平行化),並附上擁有者做決定所需的數據。向使用者展示表格,並獲得哪些行要推送的許可。將結果存檔至 ${MAKERSKILLS_CONFIG:-$HOME/.config/makerskills}/ci-audit/archive/<YYYY-MM-DD>-<scope>.md。
步驟 6 — 修復流程
一個儲存庫搭配一個工作人員。在支援子代理的主機上,可以平行處理多個儲存庫,使用相同的簡報:全新克隆、先開 Issue、以 Issue 編號命名分支、小型提交、在 PR 描述中包含前後對比數據。
對於每個修復:
- 開啟一個附有測量結果的 Issue。
- 在分支上進行修改。在本機執行 lint 與測試,並透過結束碼確認。
- 驗證:推送,然後重新執行該 PR 的 CI,使快取變暖,並與多次舊執行的基線進行比較。對於管線修復,使用小限制從分支觸發工作流程。
- 如果變更沒有幫助(這種情況確實會發生,例如 Playwright 快取),附上數據關閉 PR。這是一個結果,而非失敗。
- 在審查通過且檢查綠燈後,合併到整合分支。
- 對於任何排程相關的變更,等待使用者同意後,再開啟發佈 PR 到預設分支。在此之前,生產環境不會有任何變更。
步驟 7 — 驗證與記錄
- 在下一次排程執行後,讀取其時間與日誌。確認修復在生產環境中成立,而不僅僅在分支上。
- 將結果附加到存檔檔案:每個儲存庫的前後對比、哪些未合併就關閉了,以及新的注意事項。
- 建議每月重新執行審計,或每當感覺 CI 變慢時執行。設定週期性提醒(使用
loopify)效果很好。
可組合搭配的技能
loopify— 排程每月重新審計,或在下一個排程執行後的早上進行檢查。castmate— 讓第二個模型審查有風險的工作流程變更。unstuck— 當本該有效的修復反而測量到更慢時,在放棄之前進行分析。project-manager— 追蹤審計中發現但未實作的擁有者決定(cron 頻率、付費執行器)。
品質注意事項
- 壞掉的比慢速的更重要。 在開始計時任何事情之前,務必先檢查失敗的排程工作流程。一個每天失敗六個月的管線所造成的損失比任何快取都大。
- 只提出有暖數據的主張。 絕不報告單次冷執行的加速結果。重新執行,以多次舊執行為基線,並在 PR 中同時列出兩個數據。
- 使用計費分鐘數,而非秒數。 每個工作四捨五入意味著在私有儲存庫上,數量更少但更飽滿的工作比許多微小的工作更好。平行化是一個有成本的加速決策,而不是免費的勝利。
- 每次測試覆蓋率相同。 前後的測試數量必須寫在 PR 描述中。一個執行更少測試的更快套件不是修復。
- 排程表示預設分支。 在 cron 或管線修復合併到預設分支並至少通過一次排程執行之前,不能算完成。
- 附上數據關閉失敗的實驗。 測量結果更慢的 PR 應附上數據關閉,以免下個季度有人重試同樣的想法。
- 尊重他人的分支。 禁止修改的儲存庫只開 Issue,絕不推送。