Improve CI workflow polling: skip when no workflow files, lock onto run by ID, prefer push events
All checks were successful
Build-Test-Publish / build (linux/amd64) (push) Successful in 6s
Build-Test-Publish / build (linux/arm64) (push) Successful in 12s

This commit is contained in:
j
2026-03-11 21:48:48 +13:00
parent cd95fa0d82
commit cb4cb36ad8

152
gp
View File

@@ -543,6 +543,11 @@ wait_for_workflow() {
return 0 # silently skip if not a Gitea remote or no token return 0 # silently skip if not a Gitea remote or no token
fi fi
# Skip if no workflow files exist in the repo
if ! ls .gitea/workflows/*.yml .gitea/workflows/*.yaml .github/workflows/*.yml .github/workflows/*.yaml 2>/dev/null | grep -q .; then
return 0
fi
local spinner_chars='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏' local spinner_chars='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
local spin_idx=0 local spin_idx=0
local poll_interval=3 local poll_interval=3
@@ -581,44 +586,58 @@ wait_for_workflow() {
fi fi
# Poll API for the run # Poll API for the run
local response local run_info=""
response=$(curl -sf "${GITEA_API_BASE}/actions/runs?limit=5" -H "Authorization: ${GITEA_AUTH_HEADER}" 2>/dev/null) || true if [ "$found" = true ] && [ -n "$run_id" ]; then
# Already locked onto a run - query it directly by ID
if [ -n "$response" ]; then run_info=$(curl -sf "${GITEA_API_BASE}/actions/runs/${run_id}" -H "Authorization: ${GITEA_AUTH_HEADER}" 2>/dev/null \
# Find the run matching our commit SHA | python3 -c "
local run_info import json, sys
run_info=$(echo "$response" | python3 -c " r = json.load(sys.stdin)
print(r['id'], r['status'], r.get('conclusion',''), r.get('html_url',''))
" 2>/dev/null) || true
else
# Search for a run matching our commit SHA (prefer push events)
local response
response=$(curl -sf "${GITEA_API_BASE}/actions/runs?limit=20" -H "Authorization: ${GITEA_AUTH_HEADER}" 2>/dev/null) || true
if [ -n "$response" ]; then
run_info=$(echo "$response" | python3 -c "
import json, sys import json, sys
d = json.load(sys.stdin) d = json.load(sys.stdin)
for r in d.get('workflow_runs', []): runs = [r for r in d.get('workflow_runs', []) if r.get('head_sha','').startswith('${head_sha}')]
if r.get('head_sha','').startswith('${head_sha}'): # Prefer push-triggered runs over workflow_run-triggered ones
print(r['id'], r['status'], r.get('conclusion',''), r.get('html_url','')) push_runs = [r for r in runs if r.get('event') == 'push']
break pick = push_runs[0] if push_runs else (runs[0] if runs else None)
if pick:
print(pick['id'], pick['status'], pick.get('conclusion',''), pick.get('html_url',''))
" 2>/dev/null) || true " 2>/dev/null) || true
fi
fi
if [ -n "$run_info" ]; then if [ -n "$run_info" ]; then
if [ "$found" = false ]; then
found=true found=true
run_id=$(echo "$run_info" | awk '{print $1}') run_id=$(echo "$run_info" | awk '{print $1}')
local run_status fi
run_status=$(echo "$run_info" | awk '{print $2}') local run_status
local run_conclusion run_status=$(echo "$run_info" | awk '{print $2}')
run_conclusion=$(echo "$run_info" | awk '{print $3}') local run_conclusion
run_url=$(echo "$run_info" | awk '{print $4}') run_conclusion=$(echo "$run_info" | awk '{print $3}')
run_url=$(echo "$run_info" | awk '{print $4}')
# Fetch per-job status # Fetch per-job status
local jobs_response local jobs_response
jobs_response=$(curl -sf "${GITEA_API_BASE}/actions/runs/${run_id}/jobs" -H "Authorization: ${GITEA_AUTH_HEADER}" 2>/dev/null) || true jobs_response=$(curl -sf "${GITEA_API_BASE}/actions/runs/${run_id}/jobs" -H "Authorization: ${GITEA_AUTH_HEADER}" 2>/dev/null) || true
# Clear previous output # Clear previous output
local i local i
for ((i=0; i<prev_lines; i++)); do for ((i=0; i<prev_lines; i++)); do
printf "\033[A\033[K" printf "\033[A\033[K"
done done
if [ "$run_status" = "completed" ]; then if [ "$run_status" = "completed" ]; then
# Show final job results # Show final job results
if [ -n "$jobs_response" ]; then if [ -n "$jobs_response" ]; then
echo "$jobs_response" | python3 -c " echo "$jobs_response" | python3 -c "
import json, sys import json, sys
d = json.load(sys.stdin) d = json.load(sys.stdin)
for j in d.get('jobs', []): for j in d.get('jobs', []):
@@ -634,27 +653,27 @@ for j in d.get('jobs', []):
icon = '\033[1;33m?\033[0m' icon = '\033[1;33m?\033[0m'
print(f' {icon} {name}') print(f' {icon} {name}')
" 2>/dev/null " 2>/dev/null
fi
if [ "$run_conclusion" = "success" ]; then
print_success "CI workflow passed"
else
print_error "CI workflow failed (conclusion: $run_conclusion)"
[ -n "$run_url" ] && print_info "View: $run_url"
return 1
fi
return 0
fi fi
if [ "$run_conclusion" = "success" ]; then
print_success "CI workflow passed"
else
print_error "CI workflow failed (conclusion: $run_conclusion)"
[ -n "$run_url" ] && print_info "View: $run_url"
return 1
fi
return 0
fi
# Show per-job progress with spinner # Show per-job progress with spinner
local spin_char="${spinner_chars:$spin_idx:1}" local spin_char="${spinner_chars:$spin_idx:1}"
spin_idx=$(( (spin_idx + 1) % ${#spinner_chars} )) spin_idx=$(( (spin_idx + 1) % ${#spinner_chars} ))
local mins=$((elapsed / 60)) local mins=$((elapsed / 60))
local secs=$((elapsed % 60)) local secs=$((elapsed % 60))
prev_lines=0 prev_lines=0
if [ -n "$jobs_response" ]; then if [ -n "$jobs_response" ]; then
local job_lines local job_lines
job_lines=$(echo "$jobs_response" | python3 -c " job_lines=$(echo "$jobs_response" | python3 -c "
import json, sys import json, sys
d = json.load(sys.stdin) d = json.load(sys.stdin)
for j in d.get('jobs', []): for j in d.get('jobs', []):
@@ -667,7 +686,7 @@ for j in d.get('jobs', []):
elif status == 'completed' and conclusion == 'failure': elif status == 'completed' and conclusion == 'failure':
icon = '\033[0;31m✗\033[0m' icon = '\033[0;31m✗\033[0m'
label = '' label = ''
elif status == 'running': elif status in ('running', 'in_progress'):
icon = '${spin_char}' icon = '${spin_char}'
label = ' running' label = ' running'
elif status == 'waiting': elif status == 'waiting':
@@ -678,33 +697,40 @@ for j in d.get('jobs', []):
label = ' ' + status label = ' ' + status
print(f' {icon} {name}{label}') print(f' {icon} {name}{label}')
" 2>/dev/null) || true " 2>/dev/null) || true
if [ -n "$job_lines" ]; then if [ -n "$job_lines" ]; then
echo "$job_lines" echo "$job_lines"
prev_lines=$(echo "$job_lines" | wc -l) prev_lines=$(echo "$job_lines" | wc -l)
fi
else
printf " %s CI %s (%d:%02d)\n" "$spin_char" "$run_status" "$mins" "$secs"
prev_lines=1
fi fi
else
sleep "$poll_interval" printf " %s CI %s (%d:%02d)\n" "$spin_char" "$run_status" "$mins" "$secs"
elapsed=$((elapsed + poll_interval)) prev_lines=1
continue
fi fi
sleep "$poll_interval"
elapsed=$((elapsed + poll_interval))
continue
fi fi
# No run found yet - show waiting spinner # No run found yet - give up after 15 seconds (no workflow configured)
if [ "$elapsed" -ge 15 ]; then
local i
for ((i=0; i<prev_lines; i++)); do
printf "\033[A\033[K"
done
print_info "No CI workflow found"
return 0
fi
# Show waiting spinner
local spin_char="${spinner_chars:$spin_idx:1}" local spin_char="${spinner_chars:$spin_idx:1}"
spin_idx=$(( (spin_idx + 1) % ${#spinner_chars} )) spin_idx=$(( (spin_idx + 1) % ${#spinner_chars} ))
local mins=$((elapsed / 60))
local secs=$((elapsed % 60))
# Clear previous output # Clear previous output
local i local i
for ((i=0; i<prev_lines; i++)); do for ((i=0; i<prev_lines; i++)); do
printf "\033[A\033[K" printf "\033[A\033[K"
done done
printf " %s waiting for workflow to start (%d:%02d)\n" "$spin_char" "$mins" "$secs" printf " %s waiting for workflow to start\n" "$spin_char"
prev_lines=1 prev_lines=1
sleep "$poll_interval" sleep "$poll_interval"