diff --git a/.github/workflows/cancel-all-pending-pr-test-runs.yml b/.github/workflows/cancel-all-pending-pr-test-runs.yml deleted file mode 100644 index 71c5341e7..000000000 --- a/.github/workflows/cancel-all-pending-pr-test-runs.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Cancel All PR Test Runs (Pendings Only) - -on: - workflow_dispatch: - inputs: - workflows: - description: 'Space-separated list of workflow filenames to cancel' - required: true - type: string - default: 'pr-test.yml' - -permissions: - actions: write # Needed to cancel runs - contents: read # Needed to read repo info - -jobs: - cancel-pending-pr-test: - runs-on: ubuntu-latest - steps: - - name: Install GitHub CLI - run: sudo apt-get install -y gh jq - - - name: Cancel all pending/waiting PR-associated runs for specified workflows - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REPO: ${{ github.repository }} - run: | - # Read the space-separated string from the input into a bash array - WORKFLOW_FILES=(${{ github.event.inputs.workflows }}) - - echo "Targeting ${#WORKFLOW_FILES[@]} workflow(s): ${{ github.event.inputs.workflows }}" - - for workflow_file in "${WORKFLOW_FILES[@]}"; do - echo "--- Checking workflow: $workflow_file ---" - - gh run list \ - --repo "$REPO" \ - --workflow "$workflow_file" \ - --json databaseId,status,event \ - --limit 1000 \ - | jq -r '.[] | select((.status=="queued" or .status=="waiting") and .event=="pull_request") | .databaseId' \ - | while read run_id; do - echo "Attempting to cancel run ID: $run_id for workflow: $workflow_file" - - # The "|| echo ..." part prevents the script from crashing if cancellation fails - gh run cancel "$run_id" --repo "$REPO" || echo "⚠️ Could not cancel run $run_id (it may have already completed). Continuing..." - done - done diff --git a/.github/workflows/cancel-all-pr-test-runs.yml b/.github/workflows/cancel-all-pr-test-runs.yml deleted file mode 100644 index 67b343e2a..000000000 --- a/.github/workflows/cancel-all-pr-test-runs.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Cancel All PR Test Runs - -on: - workflow_dispatch: - inputs: - workflows: - description: 'Space-separated list of workflow filenames to cancel' - required: true - type: string - default: 'pr-test.yml' - -permissions: - actions: write # Needed to cancel runs - contents: read # Needed to read repo info - -jobs: - cancel-pr-test: - runs-on: ubuntu-latest - steps: - - name: Install GitHub CLI - run: sudo apt-get install -y gh jq - - - name: Cancel all PR-associated runs for specified workflows - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REPO: ${{ github.repository }} - run: | - # Read the space-separated string from the input into a bash array - WORKFLOW_FILES=(${{ github.event.inputs.workflows }}) - - echo "Targeting ${#WORKFLOW_FILES[@]} workflow(s): ${{ github.event.inputs.workflows }}" - - for workflow_file in "${WORKFLOW_FILES[@]}"; do - echo "--- Checking workflow: $workflow_file ---" - - gh run list \ - --repo "$REPO" \ - --workflow "$workflow_file" \ - --json databaseId,status,event \ - --limit 1000 \ - | jq -r '.[] | select((.status=="in_progress" or .status=="queued" or .status=="waiting") and .event=="pull_request") | .databaseId' \ - | while read run_id; do - echo "Attempting to cancel run ID: $run_id for workflow: $workflow_file" - - # The "|| echo ..." part prevents the script from crashing if cancellation fails - gh run cancel "$run_id" --repo "$REPO" || echo "⚠️ Could not cancel run $run_id (it may have already completed). Continuing..." - done - done diff --git a/.github/workflows/cancel-unfinished-pr-tests.yml b/.github/workflows/cancel-unfinished-pr-tests.yml new file mode 100644 index 000000000..c4f9116a0 --- /dev/null +++ b/.github/workflows/cancel-unfinished-pr-tests.yml @@ -0,0 +1,141 @@ +name: Cancel Unfinished PR Tests + +on: + workflow_dispatch: + inputs: + workflows: + description: 'Space-separated list of workflow filenames to cancel' + required: true + type: string + default: 'pr-test.yml' + +permissions: + actions: write # Needed to cancel runs + contents: read # Needed to read repo info + pull-requests: read # needed for gh pr view (labels) + +jobs: + cancel-pending-pr-test: + runs-on: ubuntu-latest + steps: + - name: Install GitHub CLI + run: sudo apt-get install -y gh jq + + - name: Cancel unfinished PR-associated runs (skip high-priority PRs) + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + WORKFLOWS: ${{ github.event.inputs.workflows || 'pr-test.yml' }} + shell: bash + run: | + set -euo pipefail + + # Read the space-separated string from the input into a bash array + read -r -a WORKFLOW_FILES <<< "${WORKFLOWS}" + + echo "Targeting ${#WORKFLOW_FILES[@]} workflow(s): ${WORKFLOWS}" + echo "" + + for workflow_file in "${WORKFLOW_FILES[@]}"; do + echo "=========================================" + echo "Workflow: $workflow_file" + echo "=========================================" + + # Get all unfinished runs + all_runs=$(gh run list \ + --repo "$REPO" \ + --workflow "$workflow_file" \ + --json databaseId,status,event,url,createdAt \ + --limit 1000 \ + | jq -c '.[] | select(.status=="queued" or .status=="waiting" or .status=="in_progress")') + + if [ -z "$all_runs" ]; then + echo "✅ No unfinished runs found" + echo "" + continue + fi + + # Count runs by event type + total_runs=$(echo "$all_runs" | wc -l) + pr_runs=$(echo "$all_runs" | jq -s '[.[] | select(.event=="pull_request")] | length') + other_runs=$(echo "$all_runs" | jq -s '[.[] | select(.event!="pull_request")] | length') + + echo "📊 Summary: $total_runs unfinished runs ($pr_runs PR-related, $other_runs other)" + echo "" + + # Process non-PR runs first + if [ "$other_runs" -gt 0 ]; then + echo "--- Non-PR Runs ---" + echo "$all_runs" | jq -c 'select(.event!="pull_request")' | while read -r run; do + run_url=$(echo "$run" | jq -r '.url') + run_event=$(echo "$run" | jq -r '.event') + run_status=$(echo "$run" | jq -r '.status') + echo " • $run_event ($run_status): $run_url" + done + echo "" + fi + + # Process PR runs + if [ "$pr_runs" -gt 0 ]; then + echo "--- PR Runs (checking for cancellation) ---" + echo "$all_runs" | jq -c 'select(.event=="pull_request")' | while read -r run; do + run_id=$(echo "$run" | jq -r '.databaseId') + run_url=$(echo "$run" | jq -r '.url') + run_status=$(echo "$run" | jq -r '.status') + + echo "" + echo "Run ($run_status): $run_url" + + # Fetch full run details to get head repository and branch info + run_details=$(gh api -H "Accept: application/vnd.github+json" \ + "repos/$REPO/actions/runs/$run_id" 2>/dev/null || true) + + if [ -z "$run_details" ]; then + echo " ⚠️ Could not fetch run details, skipping" + continue + fi + + # Get head owner and branch (works for both fork and non-fork PRs) + 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 + echo " ⚠️ Missing head info, skipping" + continue + fi + + echo " Branch: ${head_owner}:${head_branch}" + + # Find PR by searching with head=owner:branch + pr_number=$(gh api -H "Accept: application/vnd.github+json" \ + "repos/$REPO/pulls?state=open&head=${head_owner}:${head_branch}" \ + --jq '.[0].number // empty' 2>/dev/null || true) + + if [ -z "$pr_number" ]; then + echo " ⚠️ No open PR found, skipping" + continue + fi + + pr_url="https://github.com/$REPO/pull/$pr_number" + echo " PR: $pr_url" + + # Check for high priority label + labels=$(gh pr view "$pr_number" --repo "$REPO" --json labels \ + | jq -r '.labels[].name' 2>/dev/null || true) + + if echo "$labels" | grep -Fxq "high priority"; then + echo " 🛑 Skipping (high priority label)" + continue + fi + + echo " 🚫 Cancelling..." + gh run cancel "$run_id" --repo "$REPO" || echo " ⚠️ Cancellation failed" + done + fi + + echo "" + done + + echo "=========================================" + echo "✅ Processing complete" + echo "========================================="