Skip to content

Commit a368e6f

Browse files
committed
🤖 ci: improve extract_pr_logs to show in-progress job steps
1 parent 6f81504 commit a368e6f

File tree

1 file changed

+76
-43
lines changed

1 file changed

+76
-43
lines changed

scripts/extract_pr_logs.sh

Lines changed: 76 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,67 @@
11
#!/usr/bin/env bash
2-
# Extract logs from failed GitHub Actions runs for a PR
3-
# Usage: ./scripts/extract_pr_logs.sh <pr_number_or_run_id> [job_name_pattern] [--wait]
2+
# Extract logs from GitHub Actions runs for a PR (including in-progress jobs)
3+
# Usage: ./scripts/extract_pr_logs.sh <pr_number_or_run_id> [job_name_pattern] [--all]
44
#
55
# Examples:
66
# ./scripts/extract_pr_logs.sh 329 # Latest failed run for PR #329
77
# ./scripts/extract_pr_logs.sh 329 Integration # Only Integration Test jobs
8-
# ./scripts/extract_pr_logs.sh 329 --wait # Wait for logs to be available
8+
# ./scripts/extract_pr_logs.sh 329 --all # Show all jobs (not just failed)
99
# ./scripts/extract_pr_logs.sh 18640062283 # Specific run ID
1010

1111
set -euo pipefail
1212

1313
INPUT="${1:-}"
1414
JOB_PATTERN="${2:-}"
15-
WAIT_FOR_LOGS=false
15+
SHOW_ALL_JOBS=false
1616

1717
# Parse flags
18-
if [[ "$JOB_PATTERN" == "--wait" ]]; then
19-
WAIT_FOR_LOGS=true
18+
for arg in "$@"; do
19+
if [[ "$arg" == "--all" ]]; then
20+
SHOW_ALL_JOBS=true
21+
fi
22+
done
23+
24+
# Remove flags from JOB_PATTERN if they were set as second arg
25+
if [[ "$JOB_PATTERN" == "--all" ]]; then
2026
JOB_PATTERN=""
21-
elif [[ "${3:-}" == "--wait" ]]; then
22-
WAIT_FOR_LOGS=true
2327
fi
2428

2529
if [[ -z "$INPUT" ]]; then
26-
echo "❌ Usage: $0 <pr_number_or_run_id> [job_name_pattern]" >&2
30+
echo "❌ Usage: $0 <pr_number_or_run_id> [job_name_pattern] [--all]" >&2
2731
echo "" >&2
2832
echo "Examples:" >&2
29-
echo " $0 329 # Latest failed run for PR #329 (RECOMMENDED)" >&2
33+
echo " $0 329 # Latest failed run for PR #329" >&2
3034
echo " $0 329 Integration # Only Integration Test jobs from PR #329" >&2
35+
echo " $0 329 --all # Show all jobs (not just failed/in-progress)" >&2
3136
echo " $0 18640062283 # Specific run ID" >&2
3237
exit 1
3338
fi
3439

3540
# Detect if input is PR number or run ID (run IDs are much longer)
3641
if [[ "$INPUT" =~ ^[0-9]{1,5}$ ]]; then
3742
PR_NUMBER="$INPUT"
38-
echo "🔍 Finding latest failed run for PR #$PR_NUMBER..." >&2
39-
40-
# Get the latest failed run for this PR
41-
RUN_ID=$(gh pr checks "$PR_NUMBER" --json name,link,state --jq '.[] | select(.state == "FAILURE") | .link' | head -1 | sed -E 's|.*/runs/([0-9]+).*|\1|' || echo "")
43+
44+
# If --all flag is set or no failures, get latest run regardless of status
45+
if [[ "$SHOW_ALL_JOBS" == true ]]; then
46+
echo "🔍 Finding latest run for PR #$PR_NUMBER..." >&2
47+
RUN_ID=$(gh pr checks "$PR_NUMBER" --json name,link,state --jq '.[] | select(.link | contains("/runs/")) | .link' | head -1 | sed -E 's|.*/runs/([0-9]+).*|\1|' || echo "")
48+
else
49+
echo "🔍 Finding latest failed run for PR #$PR_NUMBER..." >&2
50+
# Get the latest failed run for this PR
51+
RUN_ID=$(gh pr checks "$PR_NUMBER" --json name,link,state --jq '.[] | select(.state == "FAILURE") | select(.link | contains("/runs/")) | .link' | head -1 | sed -E 's|.*/runs/([0-9]+).*|\1|' || echo "")
52+
fi
4253

4354
if [[ -z "$RUN_ID" ]]; then
4455
echo "❌ No failed runs found for PR #$PR_NUMBER" >&2
4556
echo "" >&2
4657
echo "Current check status:" >&2
4758
gh pr checks "$PR_NUMBER" 2>&1 || true
59+
echo "" >&2
60+
echo "💡 Tip: Use --all flag to see logs from any run (not just failed)" >&2
4861
exit 1
4962
fi
5063

51-
echo "📋 Found failed run: $RUN_ID" >&2
64+
echo "📋 Found run: $RUN_ID" >&2
5265
else
5366
RUN_ID="$INPUT"
5467
echo "📋 Fetching logs for run $RUN_ID..." >&2
@@ -65,12 +78,18 @@ if [[ -z "$JOBS" ]]; then
6578
exit 1
6679
fi
6780

68-
# Filter to failed jobs only (unless specific pattern requested)
69-
if [[ -z "$JOB_PATTERN" ]]; then
70-
FAILED_JOBS=$(echo "$JOBS" | jq -r 'select(.conclusion == "FAILURE" or .conclusion == "TIMED_OUT" or .conclusion == "CANCELLED")')
81+
# Filter jobs based on flags and pattern
82+
if [[ -z "$JOB_PATTERN" ]] && [[ "$SHOW_ALL_JOBS" == false ]]; then
83+
# Show failed/timed out/cancelled jobs, OR in-progress/pending jobs if no failures exist
84+
FAILED_JOBS=$(echo "$JOBS" | jq -r 'select(.conclusion == "failure" or .conclusion == "timed_out" or .conclusion == "cancelled")')
85+
IN_PROGRESS_JOBS=$(echo "$JOBS" | jq -r 'select(.status == "in_progress" or .status == "queued" or .status == "pending")')
86+
7187
if [[ -n "$FAILED_JOBS" ]]; then
72-
echo "🎯 Showing only failed jobs (use job_pattern to see others)" >&2
88+
echo "🎯 Showing only failed jobs (use --all to see all jobs)" >&2
7389
JOBS="$FAILED_JOBS"
90+
elif [[ -n "$IN_PROGRESS_JOBS" ]]; then
91+
echo "⏳ No failures yet - showing in-progress/pending jobs (use --all to see all)" >&2
92+
JOBS="$IN_PROGRESS_JOBS"
7493
fi
7594
fi
7695

@@ -111,43 +130,57 @@ suggest_local_command() {
111130
esac
112131
}
113132

133+
# Show step-by-step progress for in-progress/pending jobs
134+
show_job_steps() {
135+
local job_id="$1"
136+
local job_status="$2"
137+
138+
if [[ "$job_status" == "in_progress" ]] || [[ "$job_status" == "queued" ]] || [[ "$job_status" == "pending" ]]; then
139+
echo "" >&2
140+
echo "📊 Step-by-step status:" >&2
141+
gh api "/repos/coder/cmux/actions/jobs/$job_id" | jq -r '.steps[] | " [\(.status | ascii_upcase)] \(.name)\(if .conclusion then " (\(.conclusion))" else "" end)"' >&2
142+
echo "" >&2
143+
fi
144+
}
145+
114146
# Extract and display logs for each job
115147
for JOB_ID in $JOB_IDS; do
116148
JOB_INFO=$(echo "$JOBS" | jq -r "select(.databaseId == $JOB_ID)")
117149
JOB_NAME=$(echo "$JOB_INFO" | jq -r '.name')
118-
JOB_STATUS=$(echo "$JOB_INFO" | jq -r '.conclusion // .status')
150+
JOB_STATUS=$(echo "$JOB_INFO" | jq -r '.status')
151+
JOB_CONCLUSION=$(echo "$JOB_INFO" | jq -r '.conclusion // "N/A"')
152+
153+
# Display status: show conclusion if completed, otherwise show status
154+
if [[ "$JOB_STATUS" == "completed" ]]; then
155+
DISPLAY_STATUS="$JOB_CONCLUSION"
156+
else
157+
DISPLAY_STATUS="$JOB_STATUS"
158+
fi
119159

120160
echo "" >&2
121161
echo "════════════════════════════════════════════════════════════" >&2
122-
echo "Job: $JOB_NAME (ID: $JOB_ID) - $JOB_STATUS" >&2
162+
echo "Job: $JOB_NAME (ID: $JOB_ID)" >&2
163+
echo "Status: $DISPLAY_STATUS" >&2
123164
echo "════════════════════════════════════════════════════════════" >&2
124165

125166
# Suggest local reproduction command
126167
suggest_local_command "$JOB_NAME" >&2
127-
echo "" >&2
128-
129-
# Fetch logs with retry logic if --wait flag is set
130-
MAX_RETRIES=3
131-
RETRY_COUNT=0
168+
169+
# Show step-by-step status for in-progress/pending jobs
170+
show_job_steps "$JOB_ID" "$JOB_STATUS"
132171

133-
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
134-
# Use gh api to fetch logs (works for individual completed jobs even if run is in progress)
172+
# Try to fetch logs
173+
if [[ "$JOB_STATUS" == "completed" ]]; then
174+
# Completed job - logs should be available
135175
if gh api "/repos/coder/cmux/actions/jobs/$JOB_ID/logs" 2>/dev/null; then
136-
break
176+
echo "" >&2
137177
else
138-
RETRY_COUNT=$((RETRY_COUNT + 1))
139-
if [ $RETRY_COUNT -lt $MAX_RETRIES ] && [ "$WAIT_FOR_LOGS" = true ]; then
140-
echo "⏳ Logs not ready yet, waiting 5 seconds... (attempt $RETRY_COUNT/$MAX_RETRIES)" >&2
141-
sleep 5
142-
else
143-
echo "⚠️ Could not fetch logs for job $JOB_ID" >&2
144-
if [ "$WAIT_FOR_LOGS" = false ]; then
145-
echo " Tip: Use --wait flag to retry if logs are still processing" >&2
146-
else
147-
echo " (logs may have expired or are still processing)" >&2
148-
fi
149-
break
150-
fi
178+
echo "⚠️ Could not fetch logs for completed job $JOB_ID (logs may have expired)" >&2
179+
echo "" >&2
151180
fi
152-
done
181+
else
182+
# In-progress/pending/queued job - logs not yet available
183+
echo "ℹ️ Job is $JOB_STATUS - logs will be available when job completes" >&2
184+
echo "" >&2
185+
fi
153186
done

0 commit comments

Comments
 (0)