land-renovate 是做什麼的?
遍歷當前儲存庫中所有開放的 Renovate PR 佇列,並合併安全的 PR: 依序列舉、分類、核准 + 以 rebase-merge 方式合併(依 PR 編號升序), 對其餘 PR 勾選 rebase 核取方塊以提示重新基底,並在遇到真實失敗或 HOLD 案例時乾淨地停止。
此技能完全透過 gh 操作現有的遠端 PR。它不會呼叫 /create-commit、/create-pr 或 /wrap,也不會在本機建立提交。
引數
| 引數 | 預設值 | 說明 |
|---|---|---|
limit=N | 30 | 限制要遍歷的 PR 數量。 |
<pr-number>... | 所有 Renovate 建立的開放 PR | 以空格分隔的 PR 編號;僅對這些 PR 進行操作。 |
預設值:當前儲存庫(來自 gh repo view --json nameWithOwner)、Renovate 建立的開放 PR、
PR 編號升序排列、無標籤篩選。
工作流程
1. 解析儲存庫
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
2. 列舉 Renovate PR
列出所有開放的 Renovate 建立的 PR,從最舊(最小編號)開始:
gh pr list -R "$REPO" --author "app/renovate" --state open --limit 30 \
--json number,title,mergeable,mergeStateStatus,statusCheckRollup
按 number 升序排序並依此順序遍歷。如果指定了明確的 PR 編號作為引數,則將集合限制為這些 PR。
注意:
gh pr list經常回傳mergeable: UNKNOWN,因為 GitHub 會延遲計算可合併性。 對單一 PR 執行gh pr view <n> --json mergeable可以強制執行計算。當 PR 的mergeable為UNKNOWN時,請在分類前使用gh pr view重新讀取。
3. 分類每個 PR
使用 statusCheckRollup + mergeable + mergeStateStatus 來為每個 PR 分類:
| 分類 | 信號 | 動作 |
|---|---|---|
| GREEN | rollup 中沒有 FAILURE/CANCELLED/TIMED_OUT,沒有任何待處理項目,mergeable=MERGEABLE | 核准 + rebase-merge(步驟 4) |
| CONFLICTING | mergeable=CONFLICTING 或 mergeStateStatus=DIRTY | 勾選 rebase 核取方塊(步驟 5),監控 |
| REAL_FAILURE | rollup 中包含無法由升級後處理程序自動修復的 FAILURE | 跳過;留給人工處理 |
| HOLD | 需要跨檔案協調(人工檢查清單 — 請見下方) | 呈現給人類;不要繼續進行 |
當 CheckRun 的 status != COMPLETED 或 StatusContext 的 state 為 PENDING/EXPECTED
時,rollup 中的檢查視為待處理。當 CheckRun.conclusion 為 FAILURE/CANCELLED/TIMED_OUT/
ACTION_REQUIRED/STARTUP_FAILURE,或 StatusContext.state 為 FAILURE/
ERROR 時,視為失敗。
HOLD 檢查清單(人工判斷 — 非硬編碼)
HOLD 檢測是 AI 代理所做的判斷,而不是自動化規則。當隔離合併某個 PR 會破壞位於另一個檔案中的內容時, 將該 PR 視為 HOLD 候選者,例如:
- terraform-version 固定版本不符 — Terraform 提供者/CLI 升級需要在其他地方更新對應的固定版本(例如
.terraform-version、CI 工作流程或required_version限制),然後才能安全合併。 - schema 升級需要程式碼編輯 — 依賴項升級的新的主要版本變更了手寫程式碼仍依賴的 schema/類型;升級後鉤子無法產生程式碼編輯。
- 任何變更日誌中要求進行升級後作業無法執行的協調編輯的升級。
當 PR 看起來像 HOLD 時,將其呈現給使用者並詢問 — 不要自動合併,也不要勾選 rebase 核取方塊。繼續遍歷佇列的其餘部分。
4. 核准 + 合併 (GREEN)
gh pr review "$PR" -R "$REPO" --approve \
--body "LGTM — 作為 Renovate 批次上線的一部分自動核准。"
gh pr merge "$PR" -R "$REPO" --rebase --delete-branch
5. 勾選 rebase 核取方塊 (CONFLICTING)
翻轉 Renovate 的 rebase 核取方塊,以便它重新基底分支,然後監控:
body=$(gh pr view "$PR" -R "$REPO" --json body -q .body)
new=$(printf '%s' "$body" | sed 's|^\( *\)\- \[ \] <!-- rebase-check -->|\1- [x] <!-- rebase-check -->|')
printf '%s' "$new" | gh pr edit "$PR" -R "$REPO" --body-file - >/dev/null
在勾選核取方塊之前,先擷取當前 head SHA 作為基準線,然後執行監控(步驟 6), 這樣您就可以區分重新基底與起始狀態:
BASELINE=$(gh pr view "$PR" -R "$REPO" --json headRefOid -q .headRefOid)
永遠不要在 REAL_FAILURE 上勾選 rebase 核取方塊 — 這會浪費 Renovate 的資源並隱藏真正的問題。
6. 監控直到穩定
附帶的 scripts/monitor-renovate-pr.sh 腳本會輪詢單一 PR,直到其檢查穩定,
並輸出一個由 AI 代理透過監控工具使用的判決。
scripts/monitor-renovate-pr.sh <pr-number> <repo> <baseline-head-sha-short>
- 每 45 秒(可透過
POLL_INTERVAL覆蓋)輪詢gh pr view --json headRefOid,mergeable,mergeStateStatus,statusCheckRollup,並僅在簽名${head:0:9}|<mergeable>:<state>|ok=N pend=M fail=K變更時輸出一行。 - 一旦 head 已離開基準線、沒有待處理的檢查,且簽名在連續兩次輪詢中保持穩定,則發出判決。
- 最終的 stdout 行是以下之一:
GREEN: #<n> ready to merge→ 返回步驟 4 核准 + 合併。NOT-GREEN: #<n> settled failures=X mergeable=Y state=Z→ 重新分類;它現在是 REAL_FAILURE 或 HOLD。
- 可選環境變數:
POLL_INTERVAL(秒,預設 45)、MAX_POLLS(在 N 次輪詢後放棄,0= 無限制;耗盡時發出NOT-GREEN: #<n> timeout ...)。
為什麼使用輪詢迴圈而不是 gh pr checks --watch
gh pr checks <n> --watch 對於一個已經可以合併且僅在執行檢查的 PR 來說很好,
但對於此技能所針對的重新基底路徑,它會產生誤導:
- 它在過時的 head 上以綠色退出。 剛勾選 rebase 核取方塊後,PR 的_當前_檢查已經處於終端狀態——它們在重新基底前的(衝突)head 上通過了。
--watch看到「沒有待處理的檢查」,並立即回傳成功,甚至在 Renovate 重新基底之前。而head moved off baseline條件正是為了防止這種虛假的綠色。 - 它只知道檢查,不知道可合併性。 GREEN 判決需要
mergeable=MERGEABLE+mergeStateStatus=CLEAN,而 CONFLICTING 是透過這些欄位_檢測_的——gh pr checks從不回傳這些欄位。一次gh pr view輪詢就可以一次涵蓋兩者。 - head 可以移動兩次(Renovate 推送,然後應用程式機器人進行升級後推送)。這兩者之間存在一個時間窗口,其中已知的檢查暫時完成;
--watch可以在這個間隙退出。而「沒有待處理且兩次輪詢穩定」的保護可以安全度過這個間隙。
7. 預期的重新基底後提交鏈
在勾選 rebase 核取方塊後(或 Renovate 自行重新基底),GREEN 上線通常會經歷以下鏈條——了解它就能判斷監控的變動是預期的,而不是失敗:
- Renovate 推送一個新的 head,作為
renovate[bot]。 pull_request工作流程觸發。check.yml的升級後步驟執行eslint --fix、prettier --write、vitest --update、projen和beachball變更條目。- 如果升級後步驟產生了差異,則
commit-upgrade-changes作業會透過actions/create-github-app-token@v2鑄造一個應用程式權杖,並將修正推送為<app-slug>[bot]。該機器人推送會重新觸發pull_request工作流程,因此 head 會第二次移動,檢查會重新執行。 - 最終就緒狀態:
mergeable=MERGEABLE、mergeStateStatus=CLEAN、所有檢查SUCCESS/SKIPPED。
由於 head 可以移動兩次(Renovate,然後應用程式機器人),監控是根據「head 離開基準線 + 沒有待處理 + 兩次穩定輪詢」來決定判決,而不是根據它看到的第一個推送。
停止條件
- 沒有剩餘的 GREEN PR — 完成。
- REAL_FAILURE — 跳過它,繼續下一個 PR;永遠不要自動重新基底 REAL_FAILURE。
- HOLD 候選者 — 將其呈現給人類決定;不要自動合併。
- 使用者取消。
限制
- 提交主題不得包含問題/PR 參考(專案規則)。此處不適用於合併遠端 PR,但如果此技能將來擴展為建立本機提交,請將參考保留在主題之外——將它們放在正文中。請參閱
/create-commit。 - 永遠不要在 REAL_FAILURE 上勾選 rebase 核取方塊。
- 永遠不要自動合併 HOLD 候選者。
- HOLD 檢測是人工檢查清單,而不是硬編碼規則。識別上述類別並呈現候選者;不要嘗試自動化決策。
測試筆記
乾運作分類
列舉並查看分類桶,不進行任何實際操作:
gh pr list -R "$REPO" --author "app/renovate" --state open \
--json number,title,mergeable,mergeStateStatus,statusCheckRollup \
| jq -r '.[] | "\(.number)\t\(.mergeable)\t\(.mergeStateStatus)\t\(.title)"'
為每個 PR 新增一個 rollup 摘要,以找出待處理/失敗的檢查:
gh pr list -R "$REPO" --author "app/renovate" --state open \
--json number,statusCheckRollup \
| jq -r '.[] | "\(.number)\t" + ([.statusCheckRollup[] | .conclusion // .state] | join(","))'
監控冒煙測試
針對一個已知的 PR 執行監控,使用虛擬的基準線 SHA(這樣 head 已經算作「已移動」), 並使用短間隔來觀察狀態行和最終判決:
POLL_INTERVAL=2 MAX_POLLS=4 \
scripts/monitor-renovate-pr.sh <known-pr> "$REPO" deadbeef0
您應該會看到每個簽名變更對應一行狀態行,然後是 GREEN: / NOT-GREEN: 判決。
將 PR 的真實 head 作為基準線傳遞,則可以測試無重新基底路徑:head 從不移動,
因此它永遠不會穩定,並且執行會在 MAX_POLLS 超時時結束。
不涵蓋的範圍
- 硬編碼的 HOLD 檢測規則(從上述人工檢查清單開始;稍後擴展)。
- 將此技能連接到任何協調層。