11#! /usr/bin/env bash
22set -euo pipefail
33
4- # Wait for PR checks to complete
5- # Usage: ./scripts/wait_pr_checks.sh <pr_number>
4+ # Wait for PR checks to complete.
5+ # Usage: ./scripts/wait_pr_checks.sh <pr_number> [--once]
6+ #
7+ # Exits:
8+ # 0 - PR checks and mergeability gates passed
9+ # 1 - terminal failure (conflicts, failing checks, unresolved comments, etc.)
10+ # 10 - still waiting for checks/mergeability (only in --once mode)
611
7- if [ $# -eq 0 ]; then
8- echo " Usage: $0 <pr_number>"
12+ if [ $# -lt 1 ] || [ $# -gt 2 ]; then
13+ echo " Usage: $0 <pr_number> [--once] "
914 exit 1
1015fi
1116
1217PR_NUMBER=$1
18+ MODE=" wait"
19+
20+ if [ $# -eq 2 ]; then
21+ if [ " $2 " = " --once" ]; then
22+ MODE=" once"
23+ else
24+ echo " ❌ Unknown argument: '$2 '" >&2
25+ echo " Usage: $0 <pr_number> [--once]" >&2
26+ exit 1
27+ fi
28+ fi
29+
30+ SCRIPT_DIR=$( cd -- " $( dirname -- " ${BASH_SOURCE[0]} " ) " && pwd)
31+ CHECK_REVIEWS_SCRIPT=" $SCRIPT_DIR /check_pr_reviews.sh"
32+ CHECK_CODEX_COMMENTS_SCRIPT=" $SCRIPT_DIR /check_codex_comments.sh"
33+
34+ if ! [[ " $PR_NUMBER " =~ ^[0-9]+$ ]]; then
35+ echo " ❌ PR number must be numeric. Got: '$PR_NUMBER '" >&2
36+ exit 1
37+ fi
38+
39+ for helper in " $CHECK_REVIEWS_SCRIPT " " $CHECK_CODEX_COMMENTS_SCRIPT " ; do
40+ if [ ! -x " $helper " ]; then
41+ echo " ❌ assertion failed: missing executable helper script: $helper " >&2
42+ exit 1
43+ fi
44+ done
1345
1446# Check for dirty working tree
1547if ! git diff-index --quiet HEAD --; then
@@ -73,61 +105,112 @@ if [[ "$LOCAL_HASH" != "$REMOTE_HASH" ]]; then
73105 exit 1
74106fi
75107
76- echo " ⏳ Waiting for PR #$PR_NUMBER checks to complete..."
77- echo " "
108+ LAST_MERGE_STATE=" UNKNOWN"
109+
110+ CHECK_PR_CHECKS_ONCE () {
111+ local status
112+ local pr_state
113+ local mergeable
114+ local merge_state
115+ local checks
78116
79- while true ; do
80117 # Get PR status
81- STATUS =$( gh pr view " $PR_NUMBER " --json mergeable,mergeStateStatus,state 2> /dev/null || echo " error" )
118+ status =$( gh pr view " $PR_NUMBER " --json mergeable,mergeStateStatus,state 2> /dev/null || echo " error" )
82119
83- if [ " $STATUS " = " error" ]; then
120+ if [ " $status " = " error" ]; then
84121 echo " ❌ Failed to get PR status. Does PR #$PR_NUMBER exist?"
85- exit 1
122+ return 1
86123 fi
87124
88- PR_STATE =$( echo " $STATUS " | jq -r ' .state' )
125+ pr_state =$( echo " $status " | jq -r ' .state' )
89126
90- # Check if PR is already merged
91- if [ " $PR_STATE " = " MERGED" ]; then
92- echo " ✅ PR #$PR_NUMBER has been merged!"
93- exit 0
94- fi
127+ case " $pr_state " in
128+ MERGED)
129+ echo " ✅ PR #$PR_NUMBER has been merged!"
130+ return 0
131+ ;;
132+ CLOSED)
133+ echo " ❌ PR #$PR_NUMBER is closed (not merged)!"
134+ return 1
135+ ;;
136+ OPEN)
137+ ;;
138+ * )
139+ echo " ❌ assertion failed: unexpected PR state '$pr_state ' for PR #$PR_NUMBER " >&2
140+ return 1
141+ ;;
142+ esac
95143
96- # Check if PR is closed without merging
97- if [ " $PR_STATE " = " CLOSED" ]; then
98- echo " ❌ PR #$PR_NUMBER is closed (not merged)!"
99- exit 1
100- fi
144+ mergeable=$( echo " $status " | jq -r ' .mergeable' )
145+ merge_state=$( echo " $status " | jq -r ' .mergeStateStatus' )
146+ LAST_MERGE_STATE=" $merge_state "
101147
102- MERGEABLE=$( echo " $STATUS " | jq -r ' .mergeable' )
103- MERGE_STATE=$( echo " $STATUS " | jq -r ' .mergeStateStatus' )
148+ case " $mergeable " in
149+ MERGEABLE | CONFLICTING | UNKNOWN)
150+ ;;
151+ * )
152+ echo " ❌ assertion failed: unexpected mergeable status '$mergeable ' for PR #$PR_NUMBER " >&2
153+ return 1
154+ ;;
155+ esac
156+
157+ case " $merge_state " in
158+ BEHIND | BLOCKED | CLEAN | DIRTY | DRAFT | HAS_HOOKS | UNKNOWN | UNSTABLE)
159+ ;;
160+ * )
161+ echo " ❌ assertion failed: unexpected merge state '$merge_state ' for PR #$PR_NUMBER " >&2
162+ return 1
163+ ;;
164+ esac
104165
105166 # Check for bad merge status
106- if [ " $MERGEABLE " = " CONFLICTING" ]; then
167+ if [ " $mergeable " = " CONFLICTING" ]; then
107168 echo " ❌ PR has merge conflicts!"
108- exit 1
169+ return 1
109170 fi
110171
111- if [ " $MERGE_STATE " = " DIRTY" ]; then
172+ if [ " $merge_state " = " DIRTY" ]; then
112173 echo " ❌ PR has merge conflicts!"
113- exit 1
174+ return 1
114175 fi
115176
116- if [ " $MERGE_STATE " = " BEHIND" ]; then
177+ if [ " $merge_state " = " BEHIND" ]; then
117178 echo " ❌ PR is behind base branch. Rebase needed."
118179 echo " "
119180 echo " Run:"
120181 echo " git fetch origin"
121182 echo " git rebase origin/main"
122183 echo " git push --force-with-lease"
123- exit 1
184+ return 1
124185 fi
125186
126187 # Get check status
127- CHECKS=$( gh pr checks " $PR_NUMBER " 2>&1 || echo " pending" )
188+ checks=$( gh pr checks " $PR_NUMBER " 2>&1 || echo " pending" )
189+
190+ local has_fail=0
191+ local has_pending=0
192+ local has_pass=0
193+
194+ if echo " $checks " | grep -q " fail" ; then
195+ has_fail=1
196+ fi
197+
198+ if echo " $checks " | grep -q " pending" ; then
199+ has_pending=1
200+ fi
201+
202+ if echo " $checks " | grep -q " pass" ; then
203+ has_pass=1
204+ fi
205+
206+ if [ " $has_fail " -eq 0 ] && [ " $has_pending " -eq 0 ] && [ " $has_pass " -eq 0 ]; then
207+ echo " ❌ assertion failed: unable to classify 'gh pr checks' output for PR #$PR_NUMBER " >&2
208+ echo " $checks " >&2
209+ return 1
210+ fi
128211
129212 # Check for failures
130- if echo " $CHECKS " | grep -q " fail " ; then
213+ if [ " $has_fail " -eq 1 ] ; then
131214 echo " ❌ Some checks failed:"
132215 echo " "
133216 gh pr checks " $PR_NUMBER "
@@ -140,44 +223,92 @@ while true; do
140223 echo " make verify-vendor"
141224 echo " make test"
142225 echo " make build"
143- exit 1
226+ return 1
144227 fi
145228
146229 # Check for unresolved review comments in the hot loop
147- if ! ./scripts/check_pr_reviews.sh " $PR_NUMBER " > /dev/null 2>&1 ; then
230+ if ! " $CHECK_REVIEWS_SCRIPT " " $PR_NUMBER " > /dev/null 2>&1 ; then
148231 echo " "
149232 echo " ❌ Unresolved review comments found!"
150233 echo " 👉 Tip: run ./scripts/check_pr_reviews.sh $PR_NUMBER to list them."
151- ./scripts/check_pr_reviews.sh " $PR_NUMBER "
152- exit 1
234+ " $CHECK_REVIEWS_SCRIPT " " $PR_NUMBER "
235+ return 1
153236 fi
154237
155238 # Check if all checks passed and merge state is clean
156- if echo " $CHECKS " | grep -q " pass " && ! echo " $CHECKS " | grep -qE " pending|fail " ; then
157- if [ " $MERGE_STATE " = " CLEAN" ]; then
239+ if [ " $has_pass " -eq 1 ] && [ " $has_pending " -eq 0 ] && [ " $has_fail " -eq 0 ] ; then
240+ if [ " $merge_state " = " CLEAN" ]; then
158241 # Check for unresolved Codex comments
159242 echo " ✅ All checks passed!"
160243 echo " "
161244 gh pr checks " $PR_NUMBER "
162245 echo " "
163246 echo " 🤖 Checking for unresolved Codex comments..."
164- if ./scripts/check_codex_comments.sh " $PR_NUMBER " ; then
247+ if " $CHECK_CODEX_COMMENTS_SCRIPT " " $PR_NUMBER " ; then
165248 echo " "
166249 echo " ✅ PR is ready to merge!"
167- exit 0
168- else
169- echo " "
170- echo " ❌ Please resolve Codex comments before merging."
171- echo " 👉 Tip: use ./scripts/check_pr_reviews.sh $PR_NUMBER to list unresolved comments."
172- exit 1
250+ return 0
173251 fi
174- elif [ " $MERGE_STATE " = " BLOCKED" ]; then
175- echo " ⏳ All checks passed but still blocked (waiting for required checks)..."
252+
253+ echo " "
254+ echo " ❌ Please resolve Codex comments before merging."
255+ echo " 👉 Tip: use ./scripts/check_pr_reviews.sh $PR_NUMBER to list unresolved comments."
256+ return 1
257+ fi
258+
259+ if [ " $merge_state " = " BLOCKED" ]; then
260+ return 10
176261 fi
262+
263+ echo " ❌ assertion failed: checks passed but merge state '$merge_state ' is not supported" >&2
264+ return 1
265+ fi
266+
267+ return 10
268+ }
269+
270+ if [ " $MODE " = " once" ]; then
271+ if CHECK_PR_CHECKS_ONCE; then
272+ rc=0
273+ else
274+ rc=$?
275+ fi
276+
277+ case " $rc " in
278+ 0 | 1 | 10)
279+ exit " $rc "
280+ ;;
281+ * )
282+ echo " ❌ assertion failed: unexpected checks status code '$rc '" >&2
283+ exit 1
284+ ;;
285+ esac
286+ fi
287+
288+ echo " ⏳ Waiting for PR #$PR_NUMBER checks to complete..."
289+ echo " "
290+
291+ while true ; do
292+ if CHECK_PR_CHECKS_ONCE; then
293+ rc=0
177294 else
178- # Show current status
179- echo -ne " \r⏳ Checks in progress... (${MERGE_STATE} ) "
295+ rc=$?
180296 fi
181297
182- sleep 5
298+ case " $rc " in
299+ 0)
300+ exit 0
301+ ;;
302+ 1)
303+ exit 1
304+ ;;
305+ 10)
306+ echo -ne " \r⏳ Checks in progress... (${LAST_MERGE_STATE} ) "
307+ sleep 5
308+ ;;
309+ * )
310+ echo " ❌ assertion failed: unexpected checks status code '$rc '" >&2
311+ exit 1
312+ ;;
313+ esac
183314done
0 commit comments