318 lines
12 KiB
YAML
318 lines
12 KiB
YAML
name: List Active Runs
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
workflows:
|
|
description: 'Space-separated list of workflow filenames to check'
|
|
required: false
|
|
type: string
|
|
default: 'pr-test.yml'
|
|
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
pull-requests: read
|
|
|
|
jobs:
|
|
list-active-runs:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Install GitHub CLI
|
|
run: sudo apt-get install -y gh jq
|
|
|
|
- name: List active runs grouped by PR
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
REPO: ${{ github.repository }}
|
|
WORKFLOWS: ${{ github.event.inputs.workflows || 'pr-test.yml' }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
echo "========================================="
|
|
echo "🔍 Active Workflow Runs Report"
|
|
echo "========================================="
|
|
echo ""
|
|
|
|
# Get all workflows or specific ones
|
|
read -r -a workflow_files <<< "${WORKFLOWS}"
|
|
echo "📋 Checking specified workflows: ${WORKFLOWS}"
|
|
|
|
echo ""
|
|
|
|
# Create a temporary file to store PR data
|
|
pr_data_file=$(mktemp)
|
|
|
|
# Process each workflow
|
|
for workflow_file in ${workflow_files[@]}; do
|
|
echo "Scanning workflow: $workflow_file"
|
|
|
|
# Get all active runs (queued, waiting, in_progress)
|
|
active_runs=$(gh run list \
|
|
--repo "$REPO" \
|
|
--workflow "$workflow_file" \
|
|
--json databaseId,status,event,headBranch,createdAt,updatedAt,headSha,number,attempt \
|
|
--limit 500 \
|
|
| jq -c '.[] | select(.status=="queued" or .status=="waiting" or .status=="in_progress")')
|
|
|
|
if [ -z "$active_runs" ]; then
|
|
continue
|
|
fi
|
|
|
|
# Process each run
|
|
echo "$active_runs" | while read -r run; do
|
|
run_id=$(echo "$run" | jq -r '.databaseId')
|
|
run_status=$(echo "$run" | jq -r '.status')
|
|
run_event=$(echo "$run" | jq -r '.event')
|
|
created_at=$(echo "$run" | jq -r '.createdAt')
|
|
head_sha=$(echo "$run" | jq -r '.headSha')
|
|
run_number=$(echo "$run" | jq -r '.number')
|
|
run_attempt=$(echo "$run" | jq -r '.attempt // 1')
|
|
|
|
# Get detailed run information including jobs
|
|
run_details=$(gh api "repos/$REPO/actions/runs/$run_id" 2>/dev/null || true)
|
|
|
|
if [ -z "$run_details" ]; then
|
|
continue
|
|
fi
|
|
|
|
head_owner=$(echo "$run_details" | jq -r '.head_repository.owner.login // empty')
|
|
head_branch=$(echo "$run_details" | jq -r '.head_branch // empty')
|
|
|
|
if [ -z "$head_owner" ] || [ -z "$head_branch" ]; then
|
|
continue
|
|
fi
|
|
|
|
# Find PR number (may be empty for non-PR runs)
|
|
pr_number=$(gh api "repos/$REPO/pulls?state=open&head=${head_owner}:${head_branch}" \
|
|
--jq '.[0].number // empty' 2>/dev/null || true)
|
|
|
|
if [ -z "$pr_number" ]; then
|
|
pr_number="NO_PR"
|
|
fi
|
|
|
|
# Get jobs for this run (with pagination to avoid missing jobs)
|
|
jobs=$(gh api "repos/$REPO/actions/runs/$run_id/jobs" --paginate --jq '.jobs[]' | jq -s '.')
|
|
|
|
running_jobs=$(echo "$jobs" | jq '[.[] | select(.status=="in_progress")] | length')
|
|
queued_jobs=$(echo "$jobs" | jq '[.[] | select(.status=="queued" or .status=="waiting")] | length')
|
|
|
|
# Get runner info for running jobs
|
|
runners=$(echo "$jobs" | jq -r '.[] | select(.status=="in_progress") | .runner_name // "N/A"' | paste -sd "," -)
|
|
|
|
# Calculate queue time
|
|
current_time=$(date -u +%s)
|
|
created_time=$(date -u -d "$created_at" +%s 2>/dev/null || echo "$current_time")
|
|
queue_time=$((current_time - created_time))
|
|
queue_minutes=$((queue_time / 60))
|
|
|
|
# Store data in temporary file (unified format with event and branch)
|
|
echo "$pr_number|$workflow_file|$run_id|$run_status|$running_jobs|$queued_jobs|$runners|$queue_minutes|$created_at|$head_sha|$run_attempt|$run_event|$head_branch" >> "$pr_data_file"
|
|
done
|
|
done
|
|
|
|
echo ""
|
|
echo "========================================="
|
|
echo "📊 Active Runs Summary"
|
|
echo "========================================="
|
|
echo ""
|
|
|
|
if [ ! -s "$pr_data_file" ]; then
|
|
echo "✅ No active runs found"
|
|
rm -f "$pr_data_file"
|
|
exit 0
|
|
fi
|
|
|
|
# Get unique PR numbers (exclude NO_PR entries)
|
|
pr_numbers=$(cut -d'|' -f1 < "$pr_data_file" | grep -v '^NO_PR$' | sort -u || true)
|
|
|
|
# Separate high priority and normal PRs
|
|
high_priority_prs=()
|
|
normal_prs=()
|
|
|
|
for pr_num in $pr_numbers; do
|
|
labels=$(gh pr view "$pr_num" --repo "$REPO" --json labels \
|
|
| jq -r '.labels[].name' 2>/dev/null || true)
|
|
|
|
if echo "$labels" | grep -Fxq "high priority"; then
|
|
high_priority_prs+=($pr_num)
|
|
else
|
|
normal_prs+=($pr_num)
|
|
fi
|
|
done
|
|
|
|
# Combine: high priority first, then normal
|
|
sorted_pr_numbers=("${high_priority_prs[@]}" "${normal_prs[@]}")
|
|
|
|
pr_count=0
|
|
total_running=0
|
|
total_queued=0
|
|
|
|
for pr_num in "${sorted_pr_numbers[@]}"; do
|
|
pr_count=$((pr_count + 1))
|
|
|
|
# Get PR details
|
|
pr_info=$(gh pr view "$pr_num" --repo "$REPO" --json title,author,labels,url 2>/dev/null || true)
|
|
|
|
if [ -z "$pr_info" ]; then
|
|
continue
|
|
fi
|
|
|
|
pr_title=$(echo "$pr_info" | jq -r '.title')
|
|
pr_author=$(echo "$pr_info" | jq -r '.author.login')
|
|
pr_url=$(echo "$pr_info" | jq -r '.url')
|
|
pr_labels=$(echo "$pr_info" | jq -r '.labels[].name' | paste -sd ", " -)
|
|
|
|
if [ -z "$pr_labels" ]; then
|
|
pr_labels="(no labels)"
|
|
fi
|
|
|
|
# Add priority indicator
|
|
priority_indicator=""
|
|
if echo "$pr_labels" | grep -q "high priority"; then
|
|
priority_indicator="🔴 [HIGH PRIORITY] "
|
|
fi
|
|
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "🔗 ${priority_indicator}PR #$pr_num: $pr_title"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "👤 Author: $pr_author"
|
|
echo "🏷️ Labels: $pr_labels"
|
|
echo "🔗 URL: $pr_url"
|
|
echo ""
|
|
|
|
# Get all runs for this PR
|
|
pr_runs=$(grep "^$pr_num|" "$pr_data_file")
|
|
|
|
pr_running_total=0
|
|
pr_queued_total=0
|
|
|
|
echo "$pr_runs" | while read -r line; do
|
|
workflow=$(echo "$line" | cut -d'|' -f2)
|
|
run_id=$(echo "$line" | cut -d'|' -f3)
|
|
status=$(echo "$line" | cut -d'|' -f4)
|
|
running=$(echo "$line" | cut -d'|' -f5)
|
|
queued=$(echo "$line" | cut -d'|' -f6)
|
|
runners=$(echo "$line" | cut -d'|' -f7)
|
|
queue_min=$(echo "$line" | cut -d'|' -f8)
|
|
created=$(echo "$line" | cut -d'|' -f9)
|
|
attempt=$(echo "$line" | cut -d'|' -f11)
|
|
|
|
pr_running_total=$((pr_running_total + running))
|
|
pr_queued_total=$((pr_queued_total + queued))
|
|
|
|
run_url="https://github.com/$REPO/actions/runs/$run_id"
|
|
|
|
# Calculate retry count for this specific run
|
|
retry_count=$((attempt - 1))
|
|
|
|
# Show retry indicator
|
|
retry_indicator=""
|
|
if [ "$retry_count" -gt 0 ]; then
|
|
retry_indicator=" 🔄 Retry #$retry_count"
|
|
fi
|
|
|
|
echo " 📦 Workflow: $workflow (Run #$run_id)$retry_indicator"
|
|
echo " Status: $status"
|
|
echo " 🟢 Running jobs: $running"
|
|
echo " 🟡 Queued jobs: $queued"
|
|
|
|
if [ "$running" -gt 0 ] && [ "$runners" != "" ]; then
|
|
echo " 🖥️ Runners: $runners"
|
|
fi
|
|
|
|
if [ "$queue_min" -gt 0 ]; then
|
|
echo " ⏱️ Queue time: ${queue_min} minutes"
|
|
fi
|
|
|
|
echo " 🔗 Run URL: $run_url"
|
|
echo ""
|
|
done
|
|
|
|
# Summary for this PR
|
|
pr_running_total=$(grep "^$pr_num|" "$pr_data_file" | cut -d'|' -f5 | awk '{sum+=$1} END {print sum+0}')
|
|
pr_queued_total=$(grep "^$pr_num|" "$pr_data_file" | cut -d'|' -f6 | awk '{sum+=$1} END {print sum+0}')
|
|
|
|
total_running=$((total_running + pr_running_total))
|
|
total_queued=$((total_queued + pr_queued_total))
|
|
|
|
echo " 📊 PR Total: $pr_running_total running, $pr_queued_total queued"
|
|
echo ""
|
|
done
|
|
|
|
# --- Non-PR Runs Section ---
|
|
non_pr_runs=$(grep '^NO_PR|' "$pr_data_file" 2>/dev/null || true)
|
|
non_pr_running=0
|
|
non_pr_queued=0
|
|
|
|
if [ -n "$non_pr_runs" ]; then
|
|
echo "========================================="
|
|
echo "📦 Non-PR Runs (manual / scheduled / other)"
|
|
echo "========================================="
|
|
echo ""
|
|
|
|
echo "$non_pr_runs" | while read -r line; do
|
|
workflow=$(echo "$line" | cut -d'|' -f2)
|
|
run_id=$(echo "$line" | cut -d'|' -f3)
|
|
status=$(echo "$line" | cut -d'|' -f4)
|
|
running=$(echo "$line" | cut -d'|' -f5)
|
|
queued=$(echo "$line" | cut -d'|' -f6)
|
|
runners=$(echo "$line" | cut -d'|' -f7)
|
|
queue_min=$(echo "$line" | cut -d'|' -f8)
|
|
created=$(echo "$line" | cut -d'|' -f9)
|
|
attempt=$(echo "$line" | cut -d'|' -f11)
|
|
event=$(echo "$line" | cut -d'|' -f12)
|
|
branch=$(echo "$line" | cut -d'|' -f13)
|
|
|
|
run_url="https://github.com/$REPO/actions/runs/$run_id"
|
|
|
|
retry_count=$((attempt - 1))
|
|
retry_indicator=""
|
|
if [ "$retry_count" -gt 0 ]; then
|
|
retry_indicator=" 🔄 Retry #$retry_count"
|
|
fi
|
|
|
|
echo " 📦 Workflow: $workflow (Run #$run_id)$retry_indicator"
|
|
echo " Event: $event"
|
|
echo " Branch: $branch"
|
|
echo " Status: $status"
|
|
echo " 🟢 Running jobs: $running"
|
|
echo " 🟡 Queued jobs: $queued"
|
|
|
|
if [ "$running" -gt 0 ] && [ "$runners" != "" ]; then
|
|
echo " 🖥️ Runners: $runners"
|
|
fi
|
|
|
|
if [ "$queue_min" -gt 0 ]; then
|
|
echo " ⏱️ Queue time: ${queue_min} minutes"
|
|
fi
|
|
|
|
echo " 🔗 Run URL: $run_url"
|
|
echo ""
|
|
done
|
|
|
|
non_pr_running=$(echo "$non_pr_runs" | cut -d'|' -f5 | awk '{sum+=$1} END {print sum+0}')
|
|
non_pr_queued=$(echo "$non_pr_runs" | cut -d'|' -f6 | awk '{sum+=$1} END {print sum+0}')
|
|
non_pr_count=$(echo "$non_pr_runs" | wc -l | tr -d ' ')
|
|
|
|
total_running=$((total_running + non_pr_running))
|
|
total_queued=$((total_queued + non_pr_queued))
|
|
|
|
echo " 📊 Non-PR Total: $non_pr_running running, $non_pr_queued queued"
|
|
echo ""
|
|
fi
|
|
|
|
# Overall summary
|
|
echo "========================================="
|
|
echo "📈 Overall Summary"
|
|
echo "========================================="
|
|
echo "Total PRs with active runs: $pr_count"
|
|
echo "Total non-PR active runs: ${non_pr_count:-0}"
|
|
echo "Total running jobs: $total_running"
|
|
echo "Total queued jobs: $total_queued"
|
|
echo "========================================="
|
|
|
|
# Cleanup
|
|
rm -f "$pr_data_file"
|