pr-watch: wait out UNKNOWN mergeability; pass only an allowlisted state (improvise-edpl)
GitHub reports UNKNOWN for a while after the base moves, and PRs #172 and #179 both exited 0 there. UNKNOWN is now waited on (exit 3 on timeout), a failed check or CONFLICTING ends the wait, and the pass condition is MERGEABLE with CLEAN, UNSTABLE or HAS_HOOKS. BLOCKED, DIRTY, BEHIND, DRAFT and any unshipped state fail closed. The suite enumerates the whole table. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
+23
-15
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Waits for a PR's checks to finish and says what happened. Every rule in here
|
||||
# is one this repo got wrong first; see context/code/pr-watch.md.
|
||||
# is one this repo got wrong first; see context/code/tooling.md section 3.
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
@@ -11,10 +11,11 @@ usage: pr-watch <pr-number> [--expect <sha>] [--timeout <sec>] [--interval <sec>
|
||||
--timeout <sec> give up after this long (default 1800)
|
||||
--interval <sec> seconds between polls (default 20)
|
||||
|
||||
exit 0 every check COMPLETED and none failed
|
||||
exit 1 a check failed, or the PR is not mergeable
|
||||
exit 0 every check COMPLETED, none failed, and GitHub says MERGEABLE with a
|
||||
state of CLEAN, UNSTABLE or HAS_HOOKS
|
||||
exit 1 a check failed, or the PR is not mergeable (any other known state)
|
||||
exit 2 the head moved during the wait, or is not --expect
|
||||
exit 3 timed out with checks still running
|
||||
exit 3 timed out with checks still running or mergeability still UNKNOWN
|
||||
exit 4 usage or environment error
|
||||
EOF
|
||||
exit 4
|
||||
@@ -86,13 +87,25 @@ while :; do
|
||||
total="$(printf '%s' "$json" | jqf '[.statusCheckRollup[]?] | length')"
|
||||
running="$(printf '%s' "$json" | jqf '[.statusCheckRollup[]? | select(.status != "COMPLETED")] | length')"
|
||||
|
||||
failed="$(printf '%s' "$json" | jqf \
|
||||
'[.statusCheckRollup[]? | select(.conclusion != "SUCCESS" and .conclusion != "SKIPPED" and .conclusion != "NEUTRAL")] | length')"
|
||||
mergeable="$(printf '%s' "$json" | jqf '.mergeable')"
|
||||
state="$(printf '%s' "$json" | jqf '.mergeStateStatus')"
|
||||
|
||||
# UNKNOWN is GitHub not having computed mergeability yet, so it is waited on;
|
||||
# a red check or CONFLICTING is already an answer (improvise-edpl).
|
||||
if [ "$total" -gt 0 ] && [ "$running" -eq 0 ]; then
|
||||
break
|
||||
if [ "$failed" -gt 0 ] || [ "$mergeable" = CONFLICTING ]; then break; fi
|
||||
if [ "$mergeable" != UNKNOWN ] && [ "$state" != UNKNOWN ]; then break; fi
|
||||
fi
|
||||
|
||||
now=$(date +%s)
|
||||
if [ $((now - started)) -ge "$TIMEOUT" ]; then
|
||||
echo "pr-watch: timed out after ${TIMEOUT}s with $running of $total still running" >&2
|
||||
if [ "$total" -gt 0 ] && [ "$running" -eq 0 ]; then
|
||||
echo "pr-watch: timed out after ${TIMEOUT}s with mergeability $mergeable/$state" >&2
|
||||
else
|
||||
echo "pr-watch: timed out after ${TIMEOUT}s with $running of $total still running" >&2
|
||||
fi
|
||||
exit 3
|
||||
fi
|
||||
sleep "$INTERVAL"
|
||||
@@ -100,15 +113,10 @@ done
|
||||
|
||||
printf '%s' "$json" | jqf '.statusCheckRollup[]? | select(.conclusion != "SKIPPED") | " \(.conclusion) \(.name)"'
|
||||
|
||||
failed="$(printf '%s' "$json" | jqf \
|
||||
'[.statusCheckRollup[]? | select(.conclusion != "SUCCESS" and .conclusion != "SKIPPED" and .conclusion != "NEUTRAL")] | length')"
|
||||
mergeable="$(printf '%s' "$json" | jqf '.mergeable')"
|
||||
state="$(printf '%s' "$json" | jqf '.mergeStateStatus')"
|
||||
|
||||
echo "pr-watch: head=$head $mergeable/$state $total checks, $failed failed"
|
||||
|
||||
[ "$failed" -eq 0 ] || exit 1
|
||||
# UNSTABLE means a non-required check is unhappy; it is not a merge blocker on
|
||||
# its own, so only an outright non-mergeable state fails here.
|
||||
[ "$mergeable" != "CONFLICTING" ] || exit 1
|
||||
exit 0
|
||||
# An allowlist, so a state GitHub adds later fails closed. BLOCKED and DIRTY
|
||||
# can wear a MERGEABLE flag: context/code/tooling.md, "pr-watch and mergeability".
|
||||
[ "$mergeable" = MERGEABLE ] || exit 1
|
||||
case "$state" in CLEAN|UNSTABLE|HAS_HOOKS) exit 0 ;; *) exit 1 ;; esac
|
||||
|
||||
Reference in New Issue
Block a user