11#! /usr/bin/env bash
22# CI Failure Re-runner
33# Automatically detects failed CI jobs and re-runs them locally
4- # Usage: bin/ci-rerun-failures [pr-number]
4+ # Usage:
5+ # bin/ci-rerun-failures # Check current commit
6+ # bin/ci-rerun-failures --previous # Search recent commits for failures
7+ # bin/ci-rerun-failures 1964 # Check specific PR
58
69set -euo pipefail
710
@@ -12,27 +15,77 @@ YELLOW='\033[1;33m'
1215BLUE=' \033[0;34m'
1316NC=' \033[0m' # No Color
1417
15- PR_NUMBER=" ${1:- } "
18+ # Parse arguments
19+ USE_PREVIOUS=false
20+ PR_NUMBER=" "
21+
22+ while [[ $# -gt 0 ]]; do
23+ case $1 in
24+ --previous|--prev|-p)
25+ USE_PREVIOUS=true
26+ shift
27+ ;;
28+ * )
29+ PR_NUMBER=" $1 "
30+ shift
31+ ;;
32+ esac
33+ done
1634
1735echo -e " ${BLUE} === CI Failure Re-runner ===${NC} "
1836echo " "
1937
20- # Fetch PR status using gh CLI
38+ # Fetch PR info
2139if [ -z " $PR_NUMBER " ]; then
22- echo " Fetching current PR status..."
23- if ! gh pr view --json statusCheckRollup > /dev/null 2>&1 ; then
40+ if ! gh pr view --json number,commits > /dev/null 2>&1 ; then
2441 echo -e " ${RED} Error: Not on a PR branch or gh CLI not authenticated${NC} "
25- echo " Usage: bin/ci-rerun-failures [pr-number]"
42+ echo " Usage: bin/ci-rerun-failures [--previous] [ pr-number]"
2643 exit 1
2744 fi
28- STATUS_JSON =$( gh pr view --json statusCheckRollup, number)
29- PR_NUMBER=$( echo " $STATUS_JSON " | jq -r ' .number' )
45+ PR_INFO =$( gh pr view --json number,commits )
46+ PR_NUMBER=$( echo " $PR_INFO " | jq -r ' .number' )
3047else
31- echo " Fetching PR #$PR_NUMBER status..."
32- if ! gh pr view " $PR_NUMBER " --json statusCheckRollup > /dev/null 2>&1 ; then
48+ if ! gh pr view " $PR_NUMBER " --json number,commits > /dev/null 2>&1 ; then
3349 echo -e " ${RED} Error: PR #$PR_NUMBER not found${NC} "
3450 exit 1
3551 fi
52+ PR_INFO=$( gh pr view " $PR_NUMBER " --json number,commits)
53+ fi
54+
55+ # Determine which commit to check
56+ if [ " $USE_PREVIOUS " = true ]; then
57+ # Show recent commits and let user see which had failures
58+ echo -e " ${BLUE} Recent commits on this PR:${NC} "
59+ echo " $PR_INFO " | jq -r ' .commits[-5:] | reverse | .[] | " \(.oid[0:8]) - \(.messageHeadline)"'
60+ echo " "
61+
62+ # Check each commit from newest to oldest for failures
63+ FOUND_FAILURES=false
64+ for i in 2 3 4 5; do
65+ COMMIT_SHA=$( echo " $PR_INFO " | jq -r " .commits[-$i ].oid // empty" )
66+ if [ -z " $COMMIT_SHA " ]; then
67+ continue
68+ fi
69+
70+ echo " Checking commit ${COMMIT_SHA: 0: 8} ..."
71+ CHECK_RUNS=$( gh api " repos/{owner}/{repo}/commits/$COMMIT_SHA /check-runs" --jq ' .check_runs' 2> /dev/null || echo " []" )
72+ FAILURE_COUNT=$( echo " $CHECK_RUNS " | jq ' [.[] | select(.conclusion == "FAILURE")] | length' )
73+
74+ if [ " $FAILURE_COUNT " -gt 0 ]; then
75+ echo -e " ${GREEN} Found $FAILURE_COUNT failed check(s) in commit ${COMMIT_SHA: 0: 8}${NC} "
76+ STATUS_JSON=$( echo " $CHECK_RUNS " | jq ' {statusCheckRollup: [.[] | {name: .name, conclusion: .conclusion, status: .status}], number: ' $PR_NUMBER ' }' )
77+ FOUND_FAILURES=true
78+ break
79+ fi
80+ done
81+
82+ if [ " $FOUND_FAILURES " = false ]; then
83+ echo -e " ${YELLOW} No failures found in recent commits. Using current commit.${NC} "
84+ STATUS_JSON=$( gh pr view " $PR_NUMBER " --json statusCheckRollup,number)
85+ fi
86+ else
87+ # Use current commit (HEAD of PR)
88+ echo " Fetching current PR status..."
3689 STATUS_JSON=$( gh pr view " $PR_NUMBER " --json statusCheckRollup,number)
3790fi
3891
0 commit comments