Commit deb276faa6b1
Changed files (2)
dots
.config
claude
skills
GitHub
workflows
tools
gh-restart-failed
dots/.config/claude/skills/GitHub/workflows/RestartChecks.md
@@ -218,28 +218,54 @@ fi
**Interactive tool for restarting failed checks across multiple PRs:**
```bash
-# List and restart failed checks interactively
+# Interactive mode: List and restart failed checks with fzf
gh-restart-failed
-# Use specific repository
+# Direct mode: Restart specific PR without interactive selection
+gh-restart-failed owner/repo#123
+
+# Direct mode with current repository
+gh-restart-failed#42
+
+# Use specific repository (interactive)
gh-restart-failed owner/repo
# Ignore specific workflows (Label Checker ignored by default)
gh-restart-failed -i "build" -i "test"
-# Filter by PR labels
+# Filter by PR labels (interactive mode)
gh-restart-failed -l "bug" -l "enhancement"
+
+# Direct mode with options
+gh-restart-failed -i "Label Checker" owner/repo#123
```
**Features:**
-- Interactive fzf interface with multi-select
+- **Two modes**: Interactive (fzf) or direct (specify PR number)
+- **Direct syntax**: `owner/repo#123` to skip interactive selection
+- Interactive fzf interface with multi-select (when no PR specified)
- Preview failed checks before restarting
-- Handles multiple PRs at once
+- Handles multiple PRs at once (interactive mode)
- Filters out old runs (>1 month)
- Color-coded output with status
+- No fzf dependency required for direct mode
**Location**: `~/src/home/tools/gh-restart-failed/`
+**Usage Modes:**
+
+1. **Interactive** (requires fzf): Browse and select PRs interactively
+ ```bash
+ gh-restart-failed
+ gh-restart-failed owner/repo
+ ```
+
+2. **Direct** (no fzf needed): Immediately restart specific PR
+ ```bash
+ gh-restart-failed owner/repo#123
+ gh-restart-failed#42 # current repo
+ ```
+
## Custom Tool: Intelligent Restart (Planned)
For more sophisticated restart logic:
tools/gh-restart-failed/gh-restart-failed.sh
@@ -12,7 +12,7 @@ NC='\033[0m' # No Color
# Help message
usage() {
cat <<EOF
-Usage: gh-restart-failed [OPTIONS] [REPOSITORY]
+Usage: gh-restart-failed [OPTIONS] [REPOSITORY[#PR_NUMBER]]
List pull requests with failed checks and restart selected workflows.
@@ -24,18 +24,20 @@ Options:
Arguments:
REPOSITORY Optional repository in OWNER/REPO format or path to local repo.
If not provided, uses the current directory's repository.
+ Can include #PR_NUMBER to directly restart a specific PR (skips interactive selection).
Dependencies:
- gh (GitHub CLI)
- - fzf (fuzzy finder)
+ - fzf (fuzzy finder, only needed for interactive mode)
- jq (JSON processor)
Note:
By default, "Label Checker" workflows are ignored. Use -i to add more patterns.
Examples:
- gh-restart-failed # Use current repository
- gh-restart-failed owner/repo # Use specific GitHub repository
+ gh-restart-failed # Use current repository (interactive)
+ gh-restart-failed owner/repo#123 # Directly restart PR #123 in owner/repo
+ gh-restart-failed owner/repo # Use specific GitHub repository (interactive)
gh-restart-failed -i "build" -i "test" # Ignore build and test workflows
gh-restart-failed -l "bug" -l "enhancement" # Only show PRs with bug OR enhancement labels
gh-restart-failed /path/to/repo # Use repository at path
@@ -48,7 +50,7 @@ EOF
check_dependencies() {
local missing=()
- for cmd in gh fzf jq; do
+ for cmd in gh jq; do
if ! command -v "$cmd" &> /dev/null; then
missing+=("$cmd")
fi
@@ -67,6 +69,7 @@ LABEL_FILTERS=()
# Parse arguments
REPO_ARG=""
+PR_NUMBER=""
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
@@ -96,6 +99,11 @@ while [[ $# -gt 0 ]]; do
;;
*)
REPO_ARG="$1"
+ # Check if it contains #PR_NUMBER
+ if [[ "$REPO_ARG" =~ ^(.+)#([0-9]+)$ ]]; then
+ REPO_ARG="${BASH_REMATCH[1]}"
+ PR_NUMBER="${BASH_REMATCH[2]}"
+ fi
shift
;;
esac
@@ -103,6 +111,13 @@ done
check_dependencies
+# Check fzf only if in interactive mode (no PR_NUMBER specified)
+if [ -z "$PR_NUMBER" ] && ! command -v fzf &> /dev/null; then
+ echo -e "${RED}Error: fzf is required for interactive mode${NC}" >&2
+ echo "Please install fzf or specify a PR number directly (e.g., owner/repo#123)" >&2
+ exit 1
+fi
+
# Determine repository context
REPO_FLAG=()
if [ -n "$REPO_ARG" ]; then
@@ -125,56 +140,78 @@ if [ ${#LABEL_FILTERS[@]} -gt 0 ]; then
echo -e "${YELLOW}Filtering PRs with labels: ${LABEL_FILTERS[*]}${NC}" >&2
fi
-# Get all open PRs with their check status
-echo -e "${BLUE}Fetching pull requests...${NC}" >&2
+# If PR_NUMBER is specified, skip interactive selection
+if [ -n "$PR_NUMBER" ]; then
+ echo -e "${BLUE}Fetching PR #$PR_NUMBER...${NC}" >&2
-# Build label filter arguments for gh pr list
-LABEL_ARGS=()
-for label in "${LABEL_FILTERS[@]}"; do
- LABEL_ARGS+=(--label "$label")
-done
+ # Fetch specific PR information
+ pr_info=$(gh pr view "${REPO_FLAG[@]}" "$PR_NUMBER" \
+ --json number,title,headRefName,author \
+ 2>/dev/null)
-# Fetch PRs with detailed check information
-prs_json=$(gh pr list "${REPO_FLAG[@]}" \
- "${LABEL_ARGS[@]}" \
- --json number,title,headRefName,author,statusCheckRollup \
- --limit 100)
+ if [ -z "$pr_info" ]; then
+ echo -e "${RED}Error: PR #$PR_NUMBER not found${NC}" >&2
+ exit 1
+ fi
-# Filter PRs with failed checks and format for display
-failed_prs=$(echo "$prs_json" | jq -r '
- .[] |
- select(.statusCheckRollup // [] | any(.conclusion == "FAILURE" or .conclusion == "TIMED_OUT" or .conclusion == "STARTUP_FAILURE" or .conclusion == "ACTION_REQUIRED")) |
- {
- number: .number,
- title: .title,
- branch: .headRefName,
- author: .author.login,
- failed_checks: [.statusCheckRollup[] | select(.conclusion == "FAILURE" or .conclusion == "TIMED_OUT" or .conclusion == "STARTUP_FAILURE" or .conclusion == "ACTION_REQUIRED")]
- } |
- "#\(.number) | \(.title) | @\(.author) | \(.branch) | \(.failed_checks | length) failed"
-')
+ pr_title=$(echo "$pr_info" | jq -r '.title')
+ pr_branch=$(echo "$pr_info" | jq -r '.headRefName')
+ pr_author=$(echo "$pr_info" | jq -r '.author.login')
-if [ -z "$failed_prs" ]; then
- echo -e "${GREEN}No pull requests with failed checks found!${NC}"
- exit 0
-fi
+ # Format as if selected from interactive mode
+ selected_prs="#$PR_NUMBER | $pr_title | @$pr_author | $pr_branch | direct"
+else
+ # Interactive mode: Get all open PRs with their check status
+ echo -e "${BLUE}Fetching pull requests...${NC}" >&2
-echo -e "${YELLOW}Found pull requests with failed checks:${NC}" >&2
-echo ""
+ # Build label filter arguments for gh pr list
+ LABEL_ARGS=()
+ for label in "${LABEL_FILTERS[@]}"; do
+ LABEL_ARGS+=(--label "$label")
+ done
-# Use fzf to select PRs
-selected_prs=$(echo "$failed_prs" | fzf \
- --multi \
- --ansi \
- --header="Select pull requests to restart failed workflows (TAB to select multiple, ENTER to confirm)" \
- --preview="pr_number=\$(echo {} | cut -d'|' -f1 | tr -d '# '); gh pr checks ${REPO_FLAG[*]} \"\$pr_number\" 2>/dev/null | grep -E '(fail|FAILURE|×)' || echo 'Loading...'" \
- --preview-window=right:60%:wrap \
- --bind='ctrl-/:toggle-preview' \
- --height=80%)
+ # Fetch PRs with detailed check information
+ prs_json=$(gh pr list "${REPO_FLAG[@]}" \
+ "${LABEL_ARGS[@]}" \
+ --json number,title,headRefName,author,statusCheckRollup \
+ --limit 100)
-if [ -z "$selected_prs" ]; then
- echo -e "${YELLOW}No pull requests selected.${NC}"
- exit 0
+ # Filter PRs with failed checks and format for display
+ failed_prs=$(echo "$prs_json" | jq -r '
+ .[] |
+ select(.statusCheckRollup // [] | any(.conclusion == "FAILURE" or .conclusion == "TIMED_OUT" or .conclusion == "STARTUP_FAILURE" or .conclusion == "ACTION_REQUIRED")) |
+ {
+ number: .number,
+ title: .title,
+ branch: .headRefName,
+ author: .author.login,
+ failed_checks: [.statusCheckRollup[] | select(.conclusion == "FAILURE" or .conclusion == "TIMED_OUT" or .conclusion == "STARTUP_FAILURE" or .conclusion == "ACTION_REQUIRED")]
+ } |
+ "#\(.number) | \(.title) | @\(.author) | \(.branch) | \(.failed_checks | length) failed"
+ ')
+
+ if [ -z "$failed_prs" ]; then
+ echo -e "${GREEN}No pull requests with failed checks found!${NC}"
+ exit 0
+ fi
+
+ echo -e "${YELLOW}Found pull requests with failed checks:${NC}" >&2
+ echo ""
+
+ # Use fzf to select PRs
+ selected_prs=$(echo "$failed_prs" | fzf \
+ --multi \
+ --ansi \
+ --header="Select pull requests to restart failed workflows (TAB to select multiple, ENTER to confirm)" \
+ --preview="pr_number=\$(echo {} | cut -d'|' -f1 | tr -d '# '); gh pr checks ${REPO_FLAG[*]} \"\$pr_number\" 2>/dev/null | grep -E '(fail|FAILURE|×)' || echo 'Loading...'" \
+ --preview-window=right:60%:wrap \
+ --bind='ctrl-/:toggle-preview' \
+ --height=80%)
+
+ if [ -z "$selected_prs" ]; then
+ echo -e "${YELLOW}No pull requests selected.${NC}"
+ exit 0
+ fi
fi
echo ""