Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions tools/maintainer/train/land.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# main: when every generated file comes out unchanged the PR keeps its CI results and lands;
# otherwise auto-merge goes off and it exits 8 for a real refresh.
#
# Exit: 0 merged, 1 failing check, 2 unresolved threads, 3 timeout, 4 someone else pushed,
# Exit: 0 merged, 1 failing check, 2 unresolved threads (before or after auto-merge), 3 timeout, 4 someone else pushed,
# 5 auto-merge refused, 6 closed, 7 went DIRTY, 8 main moved under it (refresh again).
{
P=$1
Expand Down Expand Up @@ -51,20 +51,25 @@ while :; do
esac
sleep 60
done
u=$(gh api graphql -F owner="${R%/*}" -F name="${R#*/}" -F n="$P" \
-f query='query($owner:String!,$name:String!,$n:Int!){repository(owner:$owner,name:$name){pullRequest(number:$n){reviewThreads(first:100){nodes{isResolved}}}}}' \
--jq '[.data.repository.pullRequest.reviewThreads.nodes[]|select(.isResolved==false)]|length')
unresolved() {
gh api graphql -F owner="${R%/*}" -F name="${R#*/}" -F n="$P" \
-f query='query($owner:String!,$name:String!,$n:Int!){repository(owner:$owner,name:$name){pullRequest(number:$n){reviewThreads(first:100){nodes{isResolved}}}}}' \
--jq '[.data.repository.pullRequest.reviewThreads.nodes[]|select(.isResolved==false)]|length' 2>/dev/null
}
u=$(unresolved)
[ "$u" != 0 ] && { echo "#$P Corpus green but $u unresolved review thread(s)"; exit 2; }
if moved && ! still_valid; then echo "#$P main moved under it since the refresh"; exit 8; fi
gh pr merge "$P" -R "$R" --squash --auto > /dev/null 2>&1 || { echo "#$P could not enable auto-merge"; exit 5; }
echo "#$P Corpus green, 0 threads, auto-merge on"
while :; do
[ "$(date +%s)" -gt $((deadline + 3600)) ] && { echo "#$P TIMEOUT waiting for merge"; exit 3; }
[ "$(date +%s)" -gt $((deadline + 3600)) ] && { gh pr merge "$P" -R "$R" --disable-auto > /dev/null 2>&1; echo "#$P TIMEOUT waiting for merge; auto-merge off"; exit 3; }
s=$(gh pr view "$P" -R "$R" --json state,mergeStateStatus --jq '"\(.state) \(.mergeStateStatus)"' 2>/dev/null)
case $s in
MERGED*) echo "#$P MERGED as $(gh pr view "$P" -R "$R" --json mergeCommit --jq '.mergeCommit.oid[0:9]')"; exit 0 ;;
CLOSED*) echo "#$P CLOSED without merge"; exit 6 ;;
*DIRTY) gh pr merge "$P" -R "$R" --disable-auto > /dev/null 2>&1; echo "#$P went DIRTY before merging"; exit 7 ;;
# With strict up-to-date on, a branch behind main never merges; only a real refresh pushes main in.
*BEHIND) gh pr merge "$P" -R "$R" --disable-auto > /dev/null 2>&1; echo "#$P is behind main; auto-merge off"; exit 8 ;;
esac
if moved; then
[ "$(gh pr view "$P" -R "$R" --json state --jq .state 2>/dev/null)" = MERGED ] && continue
Expand All @@ -76,7 +81,14 @@ while :; do
echo "#$P main moved under it while waiting; auto-merge off"; exit 8
fi
f=$(gh pr checks "$P" -R "$R" --json name,state --jq '[.[]|select(.state=="FAILURE")|.name]|join(", ")' 2>/dev/null)
[ -n "$f" ] && { echo "#$P failing: $f"; exit 1; }
[ -n "$f" ] && { gh pr merge "$P" -R "$R" --disable-auto > /dev/null 2>&1; echo "#$P failing: $f; auto-merge off"; exit 1; }
# A reviewer can open a thread after auto-merge went on; the ruleset then holds the PR until
# the deadline, so hand it back instead of stalling the train.
case $(unresolved) in
''|*[!0-9]*|0) ;;
*) gh pr merge "$P" -R "$R" --disable-auto > /dev/null 2>&1
echo "#$P review thread opened after auto-merge went on; auto-merge off"; exit 2 ;;
esac
sleep 60
done
}
Loading