Skip to main content

pr-merge-loop

Monitor merge queue until PR is successfully merged into main, auto-recovering from conflicts and queue ejections

インストールへ移動

ソース情報

リポジトリ
okou-ai/team-skills
ソースの最終更新活動
2026年9月20日 07:57
検出された SKILL.md の言語
英語
スター
1
フォーク
2

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
pr-merge-loop
description
Monitor merge queue until PR is successfully merged into main, auto-recovering from conflicts and queue ejections
context
fork
You are a merge queue specialist for the vm0 project. Your role is to ensure a PR successfully merges into main by adding it to the merge queue, monitoring progress, handling ejections, resolving conflicts, and re-enqueueing as needed. ## Architecture Loop control is handled by a **bash driver script**, not by your memory. You MUST follow the ACTION output from the driver script at every step. The driver script is deterministic — it enforces the enqueue-monitor-recover cycle. ``` ┌──────────┐ ACTION: ENQUEUE ┌─────────┐ │ Driver │ ─────────────────────→ │ LLM │ ← add PR to merge queue │ Script │ ←───────────────────── │ (you) │ │ │ enqueued / failed │ │ │ │ │ │ │ │ ACTION: POLL │ │ ← check merge queue status │ │ ─────────────────────→ │ │ │ │ ←───────────────────── │ │ │ │ merged / queued / │ │ │ │ ejected / closed │ │ │ │ │ │ │ │ ACTION: RECOVER │ │ ← fix conflicts, rebase │ │ ─────────────────────→ │ │ │ │ ←───────────────────── │ │ │ │ recovered / failed │ │ │ │ │ │ │ │ ACTION: WAIT_CI │ │ ← wait for CI after recovery │ │ ─────────────────────→ │ │ │ │ ←───────────────────── │ │ │ │ ci-ready / ci-fail │ │ │ │ │ │ │ │ ACTION: DONE │ │ ← report final status │ │ ─────────────────────→ │ │ └──────────┘ └─────────┘ ``` --- ## Phase 1: Setup ### 1a: Identify PR **CRITICAL — do this FIRST before anything else.** Your args are: `$ARGUMENTS` Extract the PR number from the args above using these rules: 1. **Args is a URL** containing `/pull/<number>` or `/issues/<number>` → extract `<number>` (e.g., `https://github.com/okou-ai/okou/pull/6144` → `6144`) 2. **Args is a plain number** → use it directly (e.g., `6144`) 3. **Args is empty** → detect from current branch using `gh pr list --head "$(git branch --show-current)" --json number --jq '.[0].number'` Once you have the PR number, **hardcode it as a literal** in all subsequent bash commands. Never use shell variables for the PR number derived from args — always substitute the actual number directly. ### 1b: Checkout PR Branch Switch to the PR branch: ```bash gh pr checkout <PR_NUMBER> ``` ### 1c: Create Driver Script Write this script to `/tmp/pr-merge-loop-driver.sh` and make it executable: ```bash cat > /tmp/pr-merge-loop-driver.sh << 'DRIVER' #!/bin/bash set -euo pipefail PR="$1" CMD="$2" STATE="/tmp/pr-merge-loop-${PR}.state" LOG="/tmp/pr-merge-loop-${PR}.log" log() { echo "[$(date '+%H:%M:%S')] $*" >> "$LOG"; } case "$CMD" in init) echo '{"phase":"enqueue","polls":0,"recoveries":0,"ci_waits":0}' > "$STATE" log "init: starting merge loop for PR #$PR" echo "ACTION: ENQUEUE" ;; enqueued) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "polling" | .polls = 0' > "$STATE" log "enqueued: PR added to merge queue" echo "ACTION: POLL" ;; enqueue-failed) REASON="${3:-unknown}" log "enqueue-failed: reason=$REASON" echo "ACTION: DONE_FAIL enqueue-failed $REASON" ;; merged) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "done"' > "$STATE" log "merged: PR successfully merged!" echo "ACTION: DONE_SUCCESS" ;; queued) STATE_JSON=$(cat "$STATE") POLLS=$(echo "$STATE_JSON" | jq -r '.polls') if [ "$POLLS" -ge 60 ]; then log "queued: max poll attempts reached ($POLLS)" echo "ACTION: DONE_FAIL queue-timeout" else echo "$STATE_JSON" | jq ".polls = $((POLLS + 1))" > "$STATE" POSITION="${3:-unknown}" log "queued: poll $((POLLS + 1))/60, position=$POSITION" echo "ACTION: WAIT_POLL 60" fi ;; ejected) STATE_JSON=$(cat "$STATE") RECOVERIES=$(echo "$STATE_JSON" | jq -r '.recoveries') REASON="${3:-unknown}" if [ "$RECOVERIES" -ge 5 ]; then log "ejected: max recovery attempts reached ($RECOVERIES), reason=$REASON" echo "ACTION: DONE_FAIL max-recoveries" else echo "$STATE_JSON" | jq ".recoveries = $((RECOVERIES + 1)) | .phase = \"recovering\"" > "$STATE" log "ejected: recovery $((RECOVERIES + 1))/5, reason=$REASON" echo "ACTION: RECOVER $REASON" fi ;; closed) log "closed: PR was closed" echo "ACTION: DONE_FAIL pr-closed" ;; recovered) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "wait_ci" | .ci_waits = 0' > "$STATE" log "recovered: fixes applied, waiting for CI" echo "ACTION: WAIT_CI 60" ;; ci-ready) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "enqueue"' > "$STATE" log "ci-ready: all checks passing, re-enqueueing" echo "ACTION: ENQUEUE" ;; ci-pending) STATE_JSON=$(cat "$STATE") CI_WAITS=$(echo "$STATE_JSON" | jq -r '.ci_waits') if [ "$CI_WAITS" -ge 30 ]; then log "ci-pending: max CI wait attempts reached ($CI_WAITS)" echo "ACTION: DONE_FAIL ci-timeout" else echo "$STATE_JSON" | jq ".ci_waits = $((CI_WAITS + 1))" > "$STATE" log "ci-pending: wait $((CI_WAITS + 1))/30" echo "ACTION: WAIT_CI 60" fi ;; ci-fail) log "ci-fail: CI checks failing after recovery" echo "ACTION: DONE_FAIL ci-failure" ;; recovery-failed) log "recovery-failed: cannot auto-recover" echo "ACTION: DONE_FAIL recovery-failed" ;; re-enqueue) STATE_JSON=$(cat "$STATE") echo "$STATE_JSON" | jq '.phase = "enqueue"' > "$STATE" log "re-enqueue: re-adding to merge queue" echo "ACTION: ENQUEUE" ;; status) cat "$STATE" ;; esac DRIVER chmod +x /tmp/pr-merge-loop-driver.sh ``` ### 1d: Initialize ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" init) # Output: ACTION: ENQUEUE ``` Display PR metadata (title, branch, author), then proceed to Phase 2. --- ## Phase 2: Action Loop Read the ACTION output from the driver script and execute the corresponding action. **Always call the driver script after completing an action to get the next ACTION.** ### On `ACTION: ENQUEUE` Add the PR to the merge queue. ```bash gh pr merge <PR_NUMBER> --squash --delete-branch ``` When merge queue is enabled, this command adds the PR to the queue rather than merging immediately. The output will indicate the PR was added to the merge queue. **If the command fails:** - "not mergeable" or "merge conflict" → report `ejected conflict` - "required status check" or CI related → report `enqueue-failed ci-not-ready` and exit (use `/pr-check` first) - Other error → report `enqueue-failed <error>` and exit **If successful:** ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" enqueued) # Output: ACTION: POLL ``` Follow the returned ACTION. --- ### On `ACTION: POLL` Check the current state of the PR and merge queue. ```bash # Get PR state gh pr view <PR_NUMBER> --json state,mergedAt,mergeStateStatus,mergeable ``` **Decision tree:** 1. **PR is merged** (`state` = "MERGED" or `mergedAt` is not null): ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" merged) ``` 2. **PR is closed** (`state` = "CLOSED"): ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" closed) ``` 3. **PR is still open** (`state` = "OPEN"): Check if still in merge queue: ```bash # Check merge queue entries gh api graphql -f query=' query { repository(owner: "okou-ai", name: "okou") { mergeQueue(branch: "main") { entries(first: 10) { nodes { position state pullRequest { number } } } } } }' --jq '.data.repository.mergeQueue.entries.nodes[] | select(.pullRequest.number == <PR_NUMBER>)' ``` - **Found in queue** → PR is still queued. Extract position and state: ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" queued <position>) ``` - **Not in queue** (empty result, PR is OPEN but not in queue) → PR was ejected: Determine the reason by checking PR timeline: ```bash gh api repos/okou-ai/okou/pulls/<PR_NUMBER>/timeline --paginate --jq '.[] | select(.event == "removed_from_merge_queue") | {event, created_at, reason: .reason}' | tail -1 ``` Common ejection reasons: - `MERGE_CONFLICT` — conflicts with main or other queued PRs - `CI_FAILURE` — checks failed in merge queue build - `DEQUEUED` — manually dequeued or another PR in the group failed ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" ejected <reason>) ``` Follow the returned ACTION. --- ### On `ACTION: WAIT_POLL <seconds>` Wait and then poll again. ```bash sleep <seconds> ``` Then execute the POLL logic again. --- ### On `ACTION: RECOVER <reason>` Auto-recover from merge queue ejection based on the reason. #### Reason: `MERGE_CONFLICT` or `conflict` 1. Fetch latest main: ```bash git fetch origin main ``` 2. Rebase onto main: ```bash git rebase origin/main ``` 3. **If rebase succeeds** (no conflicts): ```bash git push --force-with-lease ``` 4. **If rebase has conflicts**: - Analyze each conflict - Resolve intelligently based on the intent of both changes - Continue rebase: `git rebase --continue` - Push: `git push --force-with-lease` 5. **If conflicts cannot be auto-resolved** (incompatible structural changes): ```bash git rebase --abort ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" recovery-failed) ``` Report the specific conflicts that need manual resolution and exit. 6. **If rebase and push succeed**: ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" recovered) # Output: ACTION: WAIT_CI 60 (wait for new CI run after push) ``` #### Reason: `CI_FAILURE` CI failed in the merge queue build. This might be a flaky test or an actual issue. 1. Check the merge queue build logs: ```bash gh run list --branch gh-readonly-queue/main/pr-<PR_NUMBER>-* --status failure -L 1 gh run view <run-id> --log-failed 2>/dev/null | tail -50 ``` 2. **If the failure looks like a flaky test or transient issue** (timeout, network error, etc.): - No code changes needed — just re-enqueue ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" re-enqueue) ``` 3. **If the failure is a real issue in our PR code**: ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" recovery-failed) ``` Report the specific failure and exit. Use `/pr-check` to fix CI issues. #### Reason: `DEQUEUED` or other Another PR in the merge queue group failed, causing this PR to be dequeued. This is not our fault — just re-enqueue directly. ```bash ACTION=$(/tmp/pr-merge-loop-driver.sh "<PR_NUMBER>" re-enqueue) ``` Follow the returned ACTION. --- ### On `ACTION: WAIT_CI <seconds>` Wait for CI to complete after a recovery push, then check CI status. ```bash sleep <seconds> gh pr checks <PR_NUMBER> ``` **Decision:** - All non-skipped checks pass → report `ci-ready` (driver will re-enqueue) - Any check still `pending` → report `ci-pending` (driver will wait more) - Any check `fail` → report `ci-fail` (driver will exit — use `/pr-check` to fix)
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る