Last active
April 26, 2025 15:17
-
-
Save ericboehs/ce06ffcaefb1cd4742cc5b6961ffd655 to your computer and use it in GitHub Desktop.
π Quickly list and inspect all attempts for a job in a GitHub Actions run, with options to output full links or job IDs. Handy for debugging retries.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -euo pipefail | |
usage() { | |
cat <<EOF | |
Usage: $(basename "$0") [options] <github-actions-run-url> | |
Options: | |
--only-links Only print the job links | |
--only-job-ids Only print the job IDs | |
--help Show this help message | |
Examples: | |
$(basename "$0") https://github.com/org/repo/actions/runs/123456789/job/12345 | |
$(basename "$0") --only-links https://github.com/org/repo/actions/runs/123456789/job/12345 | |
$(basename "$0") --only-job-ids https://github.com/org/repo/actions/runs/123456789/job/12345 | |
EOF | |
exit 0 | |
} | |
# --- Parse flags --- | |
ONLY_LINKS=false | |
ONLY_JOB_IDS=false | |
if [[ $# -eq 0 ]]; then | |
usage | |
fi | |
if [[ "$1" == "--help" ]]; then | |
usage | |
fi | |
if [[ $# -eq 2 ]]; then | |
case "$1" in | |
--only-links) ONLY_LINKS=true ;; | |
--only-job-ids) ONLY_JOB_IDS=true ;; | |
*) usage ;; | |
esac | |
INPUT_URL="$2" | |
elif [[ $# -eq 1 ]]; then | |
INPUT_URL="$1" | |
else | |
usage | |
fi | |
# Check for GNU grep | |
if command -v ggrep >/dev/null 2>&1; then | |
GREP="ggrep" | |
elif grep --version 2>&1 | grep -q "GNU"; then | |
GREP="grep" | |
else | |
echo "β GNU grep (supporting -P) is required. Install 'ggrep' (e.g., via 'brew install grep') or use a system with GNU grep." | |
exit 1 | |
fi | |
# Parse owner, repo, and run ID from the URL | |
OWNER=$(echo "$INPUT_URL" | "$GREP" -oP 'github\.com/\K[^/]+') | |
REPO=$(echo "$INPUT_URL" | "$GREP" -oP 'github\.com/[^/]+/\K[^/]+') | |
RUN_ID=$(echo "$INPUT_URL" | "$GREP" -oP 'runs/\K[0-9]+') | |
if [[ -z "$OWNER" || -z "$REPO" || -z "$RUN_ID" ]]; then | |
echo "β Failed to parse owner/repo/run_id from URL." | |
exit 1 | |
fi | |
# Get latest attempt number | |
LATEST_ATTEMPT=$(gh api "repos/${OWNER}/${REPO}/actions/runs/${RUN_ID}" --jq '.run_attempt') | |
# Function to fetch Test job info | |
fetch_test_job() { | |
local owner=$1 | |
local repo=$2 | |
local run_id=$3 | |
local attempt=$4 | |
local path=$5 | |
gh api "repos/${owner}/${repo}/actions/runs/${run_id}${path}/jobs" --jq ' | |
.jobs[]? | | |
select(.name == "Test") | | |
{ | |
id: .id, | |
url: .html_url, | |
conclusion: .conclusion | |
} | |
' 2>/dev/null | jq -r --arg attempt "$attempt" ' | |
if . == null then | |
"\($attempt)\tβ No Test Job\t-\t-" | |
else | |
"\($attempt)\t\(.conclusion | ascii_downcase | if test("success") then "β Passed" else "β Failed" end)\t\(.url)\t\(.id)" | |
end | |
' | |
} | |
# Fetch all attempts | |
ATTEMPTS_JSON=$(curl -s "https://github.com/${OWNER}/${REPO}/actions/runs/${RUN_ID}/new_attempts?current_attempt_number=${LATEST_ATTEMPT}&retry_blankstate=false" \ | |
-H "X-Requested-With: XMLHttpRequest" \ | |
-H "Accept: text/html" | | |
pup 'a json{}') | |
if [[ -z "$ATTEMPTS_JSON" ]]; then | |
echo "β Failed to fetch attempt data." | |
exit 1 | |
fi | |
ATTEMPTS=$(echo "$ATTEMPTS_JSON" | jq -r '.[].children[1].children[0].text | capture("Attempt #(?<n>\\d+)").n') | |
# Add latest attempt manually if missing | |
ATTEMPTS=$(echo -e "$LATEST_ATTEMPT\n$ATTEMPTS" | sort -nr | uniq) | |
# Collect all output | |
OUTPUT_LINES=() | |
for ATTEMPT in $ATTEMPTS; do | |
if [[ "$ATTEMPT" == "$LATEST_ATTEMPT" ]]; then | |
path="" | |
else | |
path="/attempts/$ATTEMPT" | |
fi | |
result=$(fetch_test_job "$OWNER" "$REPO" "$RUN_ID" "$ATTEMPT" "$path") | |
OUTPUT_LINES+=("$result") | |
done | |
# Display | |
if [[ "$ONLY_LINKS" == true ]]; then | |
printf "%s\n" "${OUTPUT_LINES[@]}" | awk -F'\t' '{print $3}' | grep -v '^-$' | |
elif [[ "$ONLY_JOB_IDS" == true ]]; then | |
printf "%s\n" "${OUTPUT_LINES[@]}" | awk -F'\t' '{print $4}' | grep -v '^-$' | |
else | |
printf "%s\n" "${OUTPUT_LINES[@]}" | awk -F'\t' '{printf "%2s %-10s %s\n", $1, $2, $3}' | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
gh-job-attempts
A lightweight utility to list a specific GitHub Actions job across all attempts of a given workflow run.
β¨ Features:
.../actions/runs/<run_id>/job/<job_id>
)--only-links
β Output just the job URLs--only-job-ids
β Output just the job IDsgh
and lightweightcurl
scrapingπ¦ Requirements
gh
(GitHub CLI)jq
pup
(HTML parser)ggrep
(macOS via Homebrew:brew install grep
)grep
on Linuxπ Usage
Example:
β‘ Installation Tip
Put the script into your
~/bin/
or any folder in your$PATH
, and make it executable:chmod +x ~/bin/gh-job-attempts
Then run it anywhere!
This script scrapes from GitHubβs internal
/new_attempts
endpoint, which is not officially supported and could change or break without notice.License
MIT