From a6c7664eb8f41386e7d601f74c5c2a0a8b7f61db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:47:31 +0000 Subject: [PATCH 01/23] Initial plan From c10c2ef209d568b71040354ecc7092bcdd76f4d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:51:31 +0000 Subject: [PATCH 02/23] Add workflow to restart old PR status checks Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/workflows/RestartPRStatusCheck.yaml | 112 ++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 .github/workflows/RestartPRStatusCheck.yaml diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/RestartPRStatusCheck.yaml new file mode 100644 index 0000000000..2221f796d2 --- /dev/null +++ b/.github/workflows/RestartPRStatusCheck.yaml @@ -0,0 +1,112 @@ +name: 'Restart Pull Request Status Check' + +on: + schedule: + - cron: '0 0 */3 * *' # Run every 3 days at midnight UTC + workflow_dispatch: # Allow manual trigger for testing + +permissions: + actions: write + checks: read + contents: read + pull-requests: read + +defaults: + run: + shell: pwsh + +jobs: + RestartStatusChecks: + runs-on: ubuntu-latest + name: Restart Old PR Status Checks + steps: + - name: Checkout + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + + - name: Check and Restart Status Checks + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + $ErrorActionPreference = "Stop" + $ProgressPreference = "SilentlyContinue" + Set-StrictMode -Version 2.0 + + Write-Host "Fetching open pull requests..." + + # Get all open pull requests + $prs = gh pr list --state open --json number,headRefName,title,url --limit 1000 | ConvertFrom-Json + + Write-Host "Found $($prs.Count) open pull requests" + + if ($prs.Count -eq 0) { + Write-Host "No open pull requests found, exiting" + exit 0 + } + + $now = [DateTime]::UtcNow + $thresholdHours = 72 + $restarted = 0 + + # Get all workflow runs for pull_request event + Write-Host "Fetching workflow runs..." + $allRuns = gh api --paginate "/repos/${{ github.repository }}/actions/runs?event=pull_request&per_page=100" | ConvertFrom-Json + $prBuildRuns = $allRuns.workflow_runs | Where-Object { $_.name -eq "Pull Request Build" } + + Write-Host "Found $($prBuildRuns.Count) 'Pull Request Build' workflow runs" + + foreach ($pr in $prs) { + Write-Host "" + Write-Host "Checking PR #$($pr.number): $($pr.title)" + + # Filter workflow runs for this specific PR + $prBuilds = $prBuildRuns | Where-Object { + $_.pull_requests | Where-Object { $_.number -eq $pr.number } + } + + if ($prBuilds.Count -eq 0) { + Write-Host " No 'Pull Request Build' workflow runs found for this PR" + continue + } + + # Get the most recent run + $latestRun = $prBuilds | Sort-Object -Property created_at -Descending | Select-Object -First 1 + + Write-Host " Latest workflow run: $($latestRun.id) (Status: $($latestRun.status), Conclusion: $($latestRun.conclusion))" + + # Check if the run is completed and successful + if ($latestRun.status -ne "completed") { + Write-Host " Workflow is still running, skipping" + continue + } + + if ($latestRun.conclusion -ne "success") { + Write-Host " Workflow conclusion is '$($latestRun.conclusion)', not 'success', skipping" + continue + } + + # Check the age of the completion + $completedAt = [DateTime]::Parse($latestRun.updated_at) + $ageInHours = ($now - $completedAt).TotalHours + + Write-Host " Completed at: $completedAt UTC (Age: $([Math]::Round($ageInHours, 2)) hours)" + + if ($ageInHours -gt $thresholdHours) { + Write-Host " Status check is older than $thresholdHours hours, restarting..." + + try { + # Re-run the workflow + gh api --method POST "/repos/${{ github.repository }}/actions/runs/$($latestRun.id)/rerun" | Out-Null + Write-Host " ✓ Successfully triggered re-run of workflow $($latestRun.id)" + $restarted++ + } + catch { + Write-Host " ✗ Failed to restart workflow: $_" + } + } + else { + Write-Host " Status check is recent enough, no action needed" + } + } + + Write-Host "" + Write-Host "Summary: Restarted $restarted workflow run(s)" From 1e77a3f7b938682762c8d973693668fbdbd1d9dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:53:34 +0000 Subject: [PATCH 03/23] Fix null check for pull_requests in workflow Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/workflows/RestartPRStatusCheck.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/RestartPRStatusCheck.yaml index 2221f796d2..38a40a69dd 100644 --- a/.github/workflows/RestartPRStatusCheck.yaml +++ b/.github/workflows/RestartPRStatusCheck.yaml @@ -60,7 +60,7 @@ jobs: # Filter workflow runs for this specific PR $prBuilds = $prBuildRuns | Where-Object { - $_.pull_requests | Where-Object { $_.number -eq $pr.number } + $_.pull_requests -and ($_.pull_requests | Where-Object { $_.number -eq $pr.number }) } if ($prBuilds.Count -eq 0) { From 50ff79e355d474146691e775808558d801c03eef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:55:32 +0000 Subject: [PATCH 04/23] Address code review feedback: improve API efficiency and date parsing Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/workflows/RestartPRStatusCheck.yaml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/RestartPRStatusCheck.yaml index 38a40a69dd..1b3f5a6520 100644 --- a/.github/workflows/RestartPRStatusCheck.yaml +++ b/.github/workflows/RestartPRStatusCheck.yaml @@ -48,9 +48,18 @@ jobs: $restarted = 0 # Get all workflow runs for pull_request event - Write-Host "Fetching workflow runs..." - $allRuns = gh api --paginate "/repos/${{ github.repository }}/actions/runs?event=pull_request&per_page=100" | ConvertFrom-Json - $prBuildRuns = $allRuns.workflow_runs | Where-Object { $_.name -eq "Pull Request Build" } + Write-Host "Fetching workflows..." + $workflows = gh api "/repos/${{ github.repository }}/actions/workflows" | ConvertFrom-Json + $prBuildWorkflow = $workflows.workflows | Where-Object { $_.name -eq "Pull Request Build" } + + if (-not $prBuildWorkflow) { + Write-Host "Could not find 'Pull Request Build' workflow, exiting" + exit 0 + } + + Write-Host "Fetching workflow runs for 'Pull Request Build' (ID: $($prBuildWorkflow.id))..." + $allRuns = gh api --paginate "/repos/${{ github.repository }}/actions/workflows/$($prBuildWorkflow.id)/runs?event=pull_request&per_page=100" | ConvertFrom-Json + $prBuildRuns = $allRuns.workflow_runs Write-Host "Found $($prBuildRuns.Count) 'Pull Request Build' workflow runs" @@ -85,7 +94,7 @@ jobs: } # Check the age of the completion - $completedAt = [DateTime]::Parse($latestRun.updated_at) + $completedAt = [DateTime]::Parse($latestRun.updated_at, [System.Globalization.CultureInfo]::InvariantCulture) $ageInHours = ($now - $completedAt).TotalHours Write-Host " Completed at: $completedAt UTC (Age: $([Math]::Round($ageInHours, 2)) hours)" From 13924195baccc571840d8b846d5975bf9145f393 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 14:25:23 +0000 Subject: [PATCH 05/23] Refactor to use gh pr checks and add retry logic Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/workflows/RestartPRStatusCheck.yaml | 111 ++++++++++++-------- 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/RestartPRStatusCheck.yaml index 1b3f5a6520..1352533098 100644 --- a/.github/workflows/RestartPRStatusCheck.yaml +++ b/.github/workflows/RestartPRStatusCheck.yaml @@ -18,7 +18,7 @@ defaults: jobs: RestartStatusChecks: runs-on: ubuntu-latest - name: Restart Old PR Status Checks + name: Restart Stale PR Status Checks steps: - name: Checkout uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 @@ -46,70 +46,93 @@ jobs: $now = [DateTime]::UtcNow $thresholdHours = 72 $restarted = 0 - - # Get all workflow runs for pull_request event - Write-Host "Fetching workflows..." - $workflows = gh api "/repos/${{ github.repository }}/actions/workflows" | ConvertFrom-Json - $prBuildWorkflow = $workflows.workflows | Where-Object { $_.name -eq "Pull Request Build" } - - if (-not $prBuildWorkflow) { - Write-Host "Could not find 'Pull Request Build' workflow, exiting" - exit 0 - } - - Write-Host "Fetching workflow runs for 'Pull Request Build' (ID: $($prBuildWorkflow.id))..." - $allRuns = gh api --paginate "/repos/${{ github.repository }}/actions/workflows/$($prBuildWorkflow.id)/runs?event=pull_request&per_page=100" | ConvertFrom-Json - $prBuildRuns = $allRuns.workflow_runs - - Write-Host "Found $($prBuildRuns.Count) 'Pull Request Build' workflow runs" + $failed = 0 + $maxRetries = 3 foreach ($pr in $prs) { Write-Host "" Write-Host "Checking PR #$($pr.number): $($pr.title)" - # Filter workflow runs for this specific PR - $prBuilds = $prBuildRuns | Where-Object { - $_.pull_requests -and ($_.pull_requests | Where-Object { $_.number -eq $pr.number }) + # Get checks for this PR + try { + $checks = gh pr checks $pr.number --json name,status,conclusion,completedAt,detailsUrl | ConvertFrom-Json } - - if ($prBuilds.Count -eq 0) { - Write-Host " No 'Pull Request Build' workflow runs found for this PR" + catch { + Write-Host " ✗ Failed to get checks for PR: $_" + $failed++ continue } - # Get the most recent run - $latestRun = $prBuilds | Sort-Object -Property created_at -Descending | Select-Object -First 1 + # Find the "Pull Request Status Check" + $statusCheck = $checks | Where-Object { $_.name -eq "Pull Request Status Check" } - Write-Host " Latest workflow run: $($latestRun.id) (Status: $($latestRun.status), Conclusion: $($latestRun.conclusion))" + if (-not $statusCheck) { + Write-Host " No 'Pull Request Status Check' found for this PR" + continue + } + + Write-Host " Check status: $($statusCheck.status), Conclusion: $($statusCheck.conclusion)" - # Check if the run is completed and successful - if ($latestRun.status -ne "completed") { - Write-Host " Workflow is still running, skipping" + # Check if the check is completed and successful + if ($statusCheck.status -ne "COMPLETED") { + Write-Host " Check is still running, skipping" continue } - if ($latestRun.conclusion -ne "success") { - Write-Host " Workflow conclusion is '$($latestRun.conclusion)', not 'success', skipping" + if ($statusCheck.conclusion -ne "SUCCESS") { + Write-Host " Check conclusion is '$($statusCheck.conclusion)', not 'SUCCESS', skipping" continue } # Check the age of the completion - $completedAt = [DateTime]::Parse($latestRun.updated_at, [System.Globalization.CultureInfo]::InvariantCulture) + if (-not $statusCheck.completedAt) { + Write-Host " No completion time available, skipping" + continue + } + + $completedAt = [DateTime]::Parse($statusCheck.completedAt, [System.Globalization.CultureInfo]::InvariantCulture) $ageInHours = ($now - $completedAt).TotalHours Write-Host " Completed at: $completedAt UTC (Age: $([Math]::Round($ageInHours, 2)) hours)" if ($ageInHours -gt $thresholdHours) { - Write-Host " Status check is older than $thresholdHours hours, restarting..." - - try { - # Re-run the workflow - gh api --method POST "/repos/${{ github.repository }}/actions/runs/$($latestRun.id)/rerun" | Out-Null - Write-Host " ✓ Successfully triggered re-run of workflow $($latestRun.id)" - $restarted++ - } - catch { - Write-Host " ✗ Failed to restart workflow: $_" + Write-Host " Status check is older than $thresholdHours hours, requesting rerun..." + + # Try to rerequest the check with retries + $success = $false + for ($retry = 0; $retry -lt $maxRetries; $retry++) { + try { + if ($retry -gt 0) { + Write-Host " Retry attempt $($retry + 1)/$maxRetries..." + Start-Sleep -Seconds 2 + } + + # Rerequest the check by re-running the workflow + # First, get the workflow run ID from the check details URL + if ($statusCheck.detailsUrl -match '/runs/(\d+)') { + $runId = $matches[1] + gh api --method POST "/repos/${{ github.repository }}/actions/runs/$runId/rerun" | Out-Null + Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" + $restarted++ + $success = $true + break + } + else { + Write-Host " ✗ Could not extract run ID from details URL: $($statusCheck.detailsUrl)" + $failed++ + break + } + } + catch { + $errorMsg = $_.Exception.Message + if ($retry -eq $maxRetries - 1) { + Write-Host " ✗ Failed to restart workflow after $maxRetries attempts: $errorMsg" + $failed++ + } + else { + Write-Host " ⚠ Attempt $($retry + 1) failed: $errorMsg" + } + } } } else { @@ -118,4 +141,6 @@ jobs: } Write-Host "" - Write-Host "Summary: Restarted $restarted workflow run(s)" + Write-Host "Summary:" + Write-Host " ✓ Successfully restarted: $restarted workflow run(s)" + Write-Host " ✗ Failed attempts: $failed" From 4cc39a1488a1a58ed70323cedcfb3cd93c831f6a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 14:27:10 +0000 Subject: [PATCH 06/23] Add exponential backoff and run ID validation Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/workflows/RestartPRStatusCheck.yaml | 24 +++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/RestartPRStatusCheck.yaml index 1352533098..58c417ad2a 100644 --- a/.github/workflows/RestartPRStatusCheck.yaml +++ b/.github/workflows/RestartPRStatusCheck.yaml @@ -103,19 +103,29 @@ jobs: for ($retry = 0; $retry -lt $maxRetries; $retry++) { try { if ($retry -gt 0) { - Write-Host " Retry attempt $($retry + 1)/$maxRetries..." - Start-Sleep -Seconds 2 + # Exponential backoff: 2s, 4s, 8s + $delaySeconds = 2 * [Math]::Pow(2, $retry - 1) + Write-Host " Retry attempt $($retry + 1)/$maxRetries (waiting $delaySeconds seconds)..." + Start-Sleep -Seconds $delaySeconds } # Rerequest the check by re-running the workflow # First, get the workflow run ID from the check details URL if ($statusCheck.detailsUrl -match '/runs/(\d+)') { $runId = $matches[1] - gh api --method POST "/repos/${{ github.repository }}/actions/runs/$runId/rerun" | Out-Null - Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" - $restarted++ - $success = $true - break + # Validate run ID is a positive integer + if ([int]$runId -gt 0) { + gh api --method POST "/repos/${{ github.repository }}/actions/runs/$runId/rerun" | Out-Null + Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" + $restarted++ + $success = $true + break + } + else { + Write-Host " ✗ Invalid run ID extracted: $runId" + $failed++ + break + } } else { Write-Host " ✗ Could not extract run ID from details URL: $($statusCheck.detailsUrl)" From 4431d75d4f5f616076563e02ca342c14ee56c663 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:52:47 +0000 Subject: [PATCH 07/23] Extract script to action and address review comments Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .../actions/RestartStalePRChecks/action.ps1 | 132 +++++++++++++++++ .../actions/RestartStalePRChecks/action.yaml | 32 ++++ .github/workflows/RestartPRStatusCheck.yaml | 137 +----------------- 3 files changed, 170 insertions(+), 131 deletions(-) create mode 100644 .github/actions/RestartStalePRChecks/action.ps1 create mode 100644 .github/actions/RestartStalePRChecks/action.yaml diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 new file mode 100644 index 0000000000..4ca27d1ade --- /dev/null +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -0,0 +1,132 @@ +param ( + [Parameter(Mandatory = $false, HelpMessage="Threshold in hours for considering a check stale")] + [int] $thresholdHours = 72, + [Parameter(Mandatory = $false, HelpMessage="Maximum number of retry attempts")] + [int] $maxRetries = 3 +) + +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" +Set-StrictMode -Version 2.0 + +Write-Host "Fetching open pull requests..." + +# Get all open pull requests +$prs = gh pr list --state open --json number,headRefName,title,url --limit 1000 | ConvertFrom-Json + +Write-Host "Found $($prs.Count) open pull requests" + +if ($prs.Count -eq 0) { + Write-Host "::notice::No open pull requests found" + exit 0 +} + +$now = [DateTime]::UtcNow +$restarted = 0 +$failed = 0 + +foreach ($pr in $prs) { + Write-Host "" + Write-Host "Checking PR #$($pr.number): $($pr.title)" + + # Get checks for this PR + try { + $checks = gh pr checks $pr.number --json name,state,bucket,completedAt,link | ConvertFrom-Json + } + catch { + Write-Host " ✗ Failed to get checks for PR: $_" + $failed++ + continue + } + + # Find the "Pull Request Status Check" + $statusCheck = $checks | Where-Object { $_.name -eq "Pull Request Status Check" } + + if (-not $statusCheck) { + Write-Host " No 'Pull Request Status Check' found for this PR" + continue + } + + Write-Host " Check state: $($statusCheck.state), Bucket: $($statusCheck.bucket)" + + # Check if the check is completed and successful + if ($statusCheck.state -ne "SUCCESS") { + Write-Host " Check state is '$($statusCheck.state)', not 'SUCCESS', skipping" + continue + } + + if ($statusCheck.bucket -ne "pass") { + Write-Host " Check bucket is '$($statusCheck.bucket)', not 'pass', skipping" + continue + } + + $completedAt = [DateTime]::Parse($statusCheck.completedAt, [System.Globalization.CultureInfo]::InvariantCulture) + $ageInHours = ($now - $completedAt).TotalHours + + Write-Host " Completed at: $completedAt UTC (Age: $([Math]::Round($ageInHours, 2)) hours)" + + if ($ageInHours -le $thresholdHours) { + Write-Host " Status check is recent enough, no action needed" + continue + } + + Write-Host " Status check is older than $thresholdHours hours, requesting rerun..." + + # Try to rerequest the check with retries + $success = $false + for ($retry = 0; $retry -lt $maxRetries; $retry++) { + try { + if ($retry -gt 0) { + # Exponential backoff: 2s, 4s, 8s + $delaySeconds = 2 * [Math]::Pow(2, $retry - 1) + Write-Host " Retry attempt $($retry + 1)/$maxRetries (waiting $delaySeconds seconds)..." + Start-Sleep -Seconds $delaySeconds + } + + # Rerequest the check by re-running the workflow + # First, get the workflow run ID from the check link + if ($statusCheck.link -match '/runs/(\d+)') { + $runId = $matches[1] + # Validate run ID is a positive integer + if ([int]$runId -gt 0) { + gh api --method POST "/repos/$env:GITHUB_REPOSITORY/actions/runs/$runId/rerun" | Out-Null + Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" + $restarted++ + $success = $true + break + } + else { + Write-Host " ✗ Invalid run ID extracted: $runId" + $failed++ + break + } + } + else { + Write-Host " ✗ Could not extract run ID from link: $($statusCheck.link)" + $failed++ + break + } + } + catch { + $errorMsg = $_.Exception.Message + if ($retry -eq $maxRetries - 1) { + Write-Host " ✗ Failed to restart workflow after $maxRetries attempts: $errorMsg" + $failed++ + } + else { + Write-Host " ⚠ Attempt $($retry + 1) failed: $errorMsg" + } + } + } +} + +Write-Host "" +Write-Host "Summary:" +Write-Host " ✓ Successfully restarted: $restarted workflow run(s)" +Write-Host " ✗ Failed attempts: $failed" + +# Add GitHub Actions job summary +Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "## PR Status Check Restart Summary" +Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" +Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully restarted: **$restarted** workflow run(s)" +Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed attempts: **$failed**" diff --git a/.github/actions/RestartStalePRChecks/action.yaml b/.github/actions/RestartStalePRChecks/action.yaml new file mode 100644 index 0000000000..3c1500e23e --- /dev/null +++ b/.github/actions/RestartStalePRChecks/action.yaml @@ -0,0 +1,32 @@ +name: Restart Stale PR Checks +author: Microsoft Corporation +description: Restart stale PR status checks that are older than a specified threshold +inputs: + thresholdHours: + description: Threshold in hours for considering a check stale + required: false + default: '72' + maxRetries: + description: Maximum number of retry attempts + required: false + default: '3' + token: + description: The GitHub token running the action + required: false + default: ${{ github.token }} +runs: + using: composite + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Restart Stale PR Checks + shell: pwsh + env: + GH_TOKEN: ${{ inputs.token }} + GITHUB_REPOSITORY: ${{ github.repository }} + run: | + ${{ github.action_path }}/action.ps1 -thresholdHours ${{ inputs.thresholdHours }} -maxRetries ${{ inputs.maxRetries }} +branding: + icon: rotate-cw + color: blue diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/RestartPRStatusCheck.yaml index 58c417ad2a..061516a580 100644 --- a/.github/workflows/RestartPRStatusCheck.yaml +++ b/.github/workflows/RestartPRStatusCheck.yaml @@ -23,134 +23,9 @@ jobs: - name: Checkout uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Check and Restart Status Checks - env: - GITHUB_TOKEN: ${{ github.token }} - run: | - $ErrorActionPreference = "Stop" - $ProgressPreference = "SilentlyContinue" - Set-StrictMode -Version 2.0 - - Write-Host "Fetching open pull requests..." - - # Get all open pull requests - $prs = gh pr list --state open --json number,headRefName,title,url --limit 1000 | ConvertFrom-Json - - Write-Host "Found $($prs.Count) open pull requests" - - if ($prs.Count -eq 0) { - Write-Host "No open pull requests found, exiting" - exit 0 - } - - $now = [DateTime]::UtcNow - $thresholdHours = 72 - $restarted = 0 - $failed = 0 - $maxRetries = 3 - - foreach ($pr in $prs) { - Write-Host "" - Write-Host "Checking PR #$($pr.number): $($pr.title)" - - # Get checks for this PR - try { - $checks = gh pr checks $pr.number --json name,status,conclusion,completedAt,detailsUrl | ConvertFrom-Json - } - catch { - Write-Host " ✗ Failed to get checks for PR: $_" - $failed++ - continue - } - - # Find the "Pull Request Status Check" - $statusCheck = $checks | Where-Object { $_.name -eq "Pull Request Status Check" } - - if (-not $statusCheck) { - Write-Host " No 'Pull Request Status Check' found for this PR" - continue - } - - Write-Host " Check status: $($statusCheck.status), Conclusion: $($statusCheck.conclusion)" - - # Check if the check is completed and successful - if ($statusCheck.status -ne "COMPLETED") { - Write-Host " Check is still running, skipping" - continue - } - - if ($statusCheck.conclusion -ne "SUCCESS") { - Write-Host " Check conclusion is '$($statusCheck.conclusion)', not 'SUCCESS', skipping" - continue - } - - # Check the age of the completion - if (-not $statusCheck.completedAt) { - Write-Host " No completion time available, skipping" - continue - } - - $completedAt = [DateTime]::Parse($statusCheck.completedAt, [System.Globalization.CultureInfo]::InvariantCulture) - $ageInHours = ($now - $completedAt).TotalHours - - Write-Host " Completed at: $completedAt UTC (Age: $([Math]::Round($ageInHours, 2)) hours)" - - if ($ageInHours -gt $thresholdHours) { - Write-Host " Status check is older than $thresholdHours hours, requesting rerun..." - - # Try to rerequest the check with retries - $success = $false - for ($retry = 0; $retry -lt $maxRetries; $retry++) { - try { - if ($retry -gt 0) { - # Exponential backoff: 2s, 4s, 8s - $delaySeconds = 2 * [Math]::Pow(2, $retry - 1) - Write-Host " Retry attempt $($retry + 1)/$maxRetries (waiting $delaySeconds seconds)..." - Start-Sleep -Seconds $delaySeconds - } - - # Rerequest the check by re-running the workflow - # First, get the workflow run ID from the check details URL - if ($statusCheck.detailsUrl -match '/runs/(\d+)') { - $runId = $matches[1] - # Validate run ID is a positive integer - if ([int]$runId -gt 0) { - gh api --method POST "/repos/${{ github.repository }}/actions/runs/$runId/rerun" | Out-Null - Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" - $restarted++ - $success = $true - break - } - else { - Write-Host " ✗ Invalid run ID extracted: $runId" - $failed++ - break - } - } - else { - Write-Host " ✗ Could not extract run ID from details URL: $($statusCheck.detailsUrl)" - $failed++ - break - } - } - catch { - $errorMsg = $_.Exception.Message - if ($retry -eq $maxRetries - 1) { - Write-Host " ✗ Failed to restart workflow after $maxRetries attempts: $errorMsg" - $failed++ - } - else { - Write-Host " ⚠ Attempt $($retry + 1) failed: $errorMsg" - } - } - } - } - else { - Write-Host " Status check is recent enough, no action needed" - } - } - - Write-Host "" - Write-Host "Summary:" - Write-Host " ✓ Successfully restarted: $restarted workflow run(s)" - Write-Host " ✗ Failed attempts: $failed" + - name: Restart Stale PR Status Checks + uses: ./.github/actions/RestartStalePRChecks + with: + thresholdHours: 72 + maxRetries: 3 + token: ${{ github.token }} From 49ff744bdb82574d374f8424a4ddbd0175a4b6fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 10:57:38 +0000 Subject: [PATCH 08/23] Use gh run rerun instead of API call Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index 4ca27d1ade..65dfc04dc7 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -89,7 +89,7 @@ foreach ($pr in $prs) { $runId = $matches[1] # Validate run ID is a positive integer if ([int]$runId -gt 0) { - gh api --method POST "/repos/$env:GITHUB_REPOSITORY/actions/runs/$runId/rerun" | Out-Null + gh run rerun $runId -R $env:GITHUB_REPOSITORY | Out-Null Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" $restarted++ $success = $true From 9cfd852f3be457325d60dadf44c3b4bfa0b0d334 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 11:01:00 +0000 Subject: [PATCH 09/23] Remove redundant bucket check and unused headRefName property Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.ps1 | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index 65dfc04dc7..9efead0e9e 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -12,7 +12,7 @@ Set-StrictMode -Version 2.0 Write-Host "Fetching open pull requests..." # Get all open pull requests -$prs = gh pr list --state open --json number,headRefName,title,url --limit 1000 | ConvertFrom-Json +$prs = gh pr list --state open --json number,title,url --limit 1000 | ConvertFrom-Json Write-Host "Found $($prs.Count) open pull requests" @@ -47,7 +47,7 @@ foreach ($pr in $prs) { continue } - Write-Host " Check state: $($statusCheck.state), Bucket: $($statusCheck.bucket)" + Write-Host " Check state: $($statusCheck.state)" # Check if the check is completed and successful if ($statusCheck.state -ne "SUCCESS") { @@ -55,11 +55,6 @@ foreach ($pr in $prs) { continue } - if ($statusCheck.bucket -ne "pass") { - Write-Host " Check bucket is '$($statusCheck.bucket)', not 'pass', skipping" - continue - } - $completedAt = [DateTime]::Parse($statusCheck.completedAt, [System.Globalization.CultureInfo]::InvariantCulture) $ageInHours = ($now - $completedAt).TotalHours From 60eddd1ef1b4d010b3647a3f22fb5bb22105f0d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:25:08 +0000 Subject: [PATCH 10/23] Remove unused success variable and fail on processing errors Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index 9efead0e9e..4715580f94 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -68,7 +68,6 @@ foreach ($pr in $prs) { Write-Host " Status check is older than $thresholdHours hours, requesting rerun..." # Try to rerequest the check with retries - $success = $false for ($retry = 0; $retry -lt $maxRetries; $retry++) { try { if ($retry -gt 0) { @@ -87,7 +86,6 @@ foreach ($pr in $prs) { gh run rerun $runId -R $env:GITHUB_REPOSITORY | Out-Null Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" $restarted++ - $success = $true break } else { @@ -125,3 +123,9 @@ Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "## PR Status Check Restart Su Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully restarted: **$restarted** workflow run(s)" Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed attempts: **$failed**" + +# Exit with error if there were any failures +if ($failed -gt 0) { + Write-Host "::error::Failed to process $failed PR(s)" + exit 1 +} From bffa485c51d14ae46c41a9b66fe6b8dd478a425b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:35:16 +0000 Subject: [PATCH 11/23] Count failed PRs instead of failed attempts Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.ps1 | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index 4715580f94..c07ad71a5b 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -68,6 +68,7 @@ foreach ($pr in $prs) { Write-Host " Status check is older than $thresholdHours hours, requesting rerun..." # Try to rerequest the check with retries + $prFailed = $false for ($retry = 0; $retry -lt $maxRetries; $retry++) { try { if ($retry -gt 0) { @@ -90,13 +91,13 @@ foreach ($pr in $prs) { } else { Write-Host " ✗ Invalid run ID extracted: $runId" - $failed++ + $prFailed = $true break } } else { Write-Host " ✗ Could not extract run ID from link: $($statusCheck.link)" - $failed++ + $prFailed = $true break } } @@ -104,13 +105,18 @@ foreach ($pr in $prs) { $errorMsg = $_.Exception.Message if ($retry -eq $maxRetries - 1) { Write-Host " ✗ Failed to restart workflow after $maxRetries attempts: $errorMsg" - $failed++ + $prFailed = $true } else { Write-Host " ⚠ Attempt $($retry + 1) failed: $errorMsg" } } } + + # Increment failed counter once per PR if any attempt failed + if ($prFailed) { + $failed++ + } } Write-Host "" From 557c998e82125cd34ba6874dbbb11d58ccd7c08a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 09:34:03 +0000 Subject: [PATCH 12/23] Use Invoke-CommandWithRetry, filter mergeable PRs, remove default params Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .../actions/RestartStalePRChecks/action.ps1 | 75 +++++++++---------- .github/workflows/RestartPRStatusCheck.yaml | 2 - 2 files changed, 35 insertions(+), 42 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index c07ad71a5b..8679331b1a 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -9,10 +9,13 @@ $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" Set-StrictMode -Version 2.0 +# Import EnlistmentHelperFunctions module +Import-Module "$PSScriptRoot\..\..\..\build\scripts\EnlistmentHelperFunctions.psm1" -DisableNameChecking + Write-Host "Fetching open pull requests..." -# Get all open pull requests -$prs = gh pr list --state open --json number,title,url --limit 1000 | ConvertFrom-Json +# Get all open pull requests with mergeable state +$prs = gh pr list --state open --json number,title,url,mergeable --limit 1000 | ConvertFrom-Json Write-Host "Found $($prs.Count) open pull requests" @@ -29,9 +32,18 @@ foreach ($pr in $prs) { Write-Host "" Write-Host "Checking PR #$($pr.number): $($pr.title)" - # Get checks for this PR + # Check if PR is mergeable + if ($pr.mergeable -ne "MERGEABLE") { + Write-Host " PR is not in MERGEABLE state (current: $($pr.mergeable)), skipping" + continue + } + + # Get checks for this PR with retry + $checks = $null try { - $checks = gh pr checks $pr.number --json name,state,bucket,completedAt,link | ConvertFrom-Json + $checks = Invoke-CommandWithRetry -ScriptBlock { + gh pr checks $pr.number --json name,state,bucket,completedAt,link | ConvertFrom-Json + } -RetryCount $maxRetries -FirstDelay 2 -MaxWaitBetweenRetries 8 } catch { Write-Host " ✗ Failed to get checks for PR: $_" @@ -67,51 +79,34 @@ foreach ($pr in $prs) { Write-Host " Status check is older than $thresholdHours hours, requesting rerun..." - # Try to rerequest the check with retries + # Try to rerequest the check with retries using Invoke-CommandWithRetry $prFailed = $false - for ($retry = 0; $retry -lt $maxRetries; $retry++) { - try { - if ($retry -gt 0) { - # Exponential backoff: 2s, 4s, 8s - $delaySeconds = 2 * [Math]::Pow(2, $retry - 1) - Write-Host " Retry attempt $($retry + 1)/$maxRetries (waiting $delaySeconds seconds)..." - Start-Sleep -Seconds $delaySeconds - } - - # Rerequest the check by re-running the workflow - # First, get the workflow run ID from the check link - if ($statusCheck.link -match '/runs/(\d+)') { - $runId = $matches[1] - # Validate run ID is a positive integer - if ([int]$runId -gt 0) { + try { + # Extract run ID from the check link + if ($statusCheck.link -match '/runs/(\d+)') { + $runId = $matches[1] + # Validate run ID is a positive integer + if ([int]$runId -gt 0) { + Invoke-CommandWithRetry -ScriptBlock { gh run rerun $runId -R $env:GITHUB_REPOSITORY | Out-Null - Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" - $restarted++ - break - } - else { - Write-Host " ✗ Invalid run ID extracted: $runId" - $prFailed = $true - break - } + } -RetryCount $maxRetries -FirstDelay 2 -MaxWaitBetweenRetries 8 + Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" + $restarted++ } else { - Write-Host " ✗ Could not extract run ID from link: $($statusCheck.link)" + Write-Host " ✗ Invalid run ID extracted: $runId" $prFailed = $true - break } } - catch { - $errorMsg = $_.Exception.Message - if ($retry -eq $maxRetries - 1) { - Write-Host " ✗ Failed to restart workflow after $maxRetries attempts: $errorMsg" - $prFailed = $true - } - else { - Write-Host " ⚠ Attempt $($retry + 1) failed: $errorMsg" - } + else { + Write-Host " ✗ Could not extract run ID from link: $($statusCheck.link)" + $prFailed = $true } } + catch { + Write-Host " ✗ Failed to restart workflow: $_" + $prFailed = $true + } # Increment failed counter once per PR if any attempt failed if ($prFailed) { diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/RestartPRStatusCheck.yaml index 061516a580..c0979b1a7c 100644 --- a/.github/workflows/RestartPRStatusCheck.yaml +++ b/.github/workflows/RestartPRStatusCheck.yaml @@ -26,6 +26,4 @@ jobs: - name: Restart Stale PR Status Checks uses: ./.github/actions/RestartStalePRChecks with: - thresholdHours: 72 - maxRetries: 3 token: ${{ github.token }} From 97e67bf8ecfb07e2693d567ad7d1e6b46e88196e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:05:14 +0000 Subject: [PATCH 13/23] Add WhatIf parameter for testing without triggering reruns Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .../actions/RestartStalePRChecks/action.ps1 | 35 ++++++++++++++----- .../actions/RestartStalePRChecks/action.yaml | 7 +++- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index 8679331b1a..a1fcdd8d37 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -2,7 +2,9 @@ param ( [Parameter(Mandatory = $false, HelpMessage="Threshold in hours for considering a check stale")] [int] $thresholdHours = 72, [Parameter(Mandatory = $false, HelpMessage="Maximum number of retry attempts")] - [int] $maxRetries = 3 + [int] $maxRetries = 3, + [Parameter(Mandatory = $false, HelpMessage="If specified, only performs read operations without triggering any reruns")] + [switch] $WhatIf ) $ErrorActionPreference = "Stop" @@ -12,6 +14,10 @@ Set-StrictMode -Version 2.0 # Import EnlistmentHelperFunctions module Import-Module "$PSScriptRoot\..\..\..\build\scripts\EnlistmentHelperFunctions.psm1" -DisableNameChecking +if ($WhatIf) { + Write-Host "::notice::Running in WhatIf mode - no workflows will be rerun" +} + Write-Host "Fetching open pull requests..." # Get all open pull requests with mergeable state @@ -87,11 +93,17 @@ foreach ($pr in $prs) { $runId = $matches[1] # Validate run ID is a positive integer if ([int]$runId -gt 0) { - Invoke-CommandWithRetry -ScriptBlock { - gh run rerun $runId -R $env:GITHUB_REPOSITORY | Out-Null - } -RetryCount $maxRetries -FirstDelay 2 -MaxWaitBetweenRetries 8 - Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" - $restarted++ + if ($WhatIf) { + Write-Host " [WhatIf] Would trigger re-run of workflow (run ID: $runId)" + $restarted++ + } + else { + Invoke-CommandWithRetry -ScriptBlock { + gh run rerun $runId -R $env:GITHUB_REPOSITORY | Out-Null + } -RetryCount $maxRetries -FirstDelay 2 -MaxWaitBetweenRetries 8 + Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" + $restarted++ + } } else { Write-Host " ✗ Invalid run ID extracted: $runId" @@ -120,13 +132,18 @@ Write-Host " ✓ Successfully restarted: $restarted workflow run(s)" Write-Host " ✗ Failed attempts: $failed" # Add GitHub Actions job summary -Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "## PR Status Check Restart Summary" +$summaryTitle = if ($WhatIf) { "## PR Status Check Restart Summary (WhatIf Mode)" } else { "## PR Status Check Restart Summary" } +Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $summaryTitle Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" +if ($WhatIf) { + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ℹ️ Running in **WhatIf mode** - no workflows were actually rerun" + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" +} Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully restarted: **$restarted** workflow run(s)" Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed attempts: **$failed**" -# Exit with error if there were any failures -if ($failed -gt 0) { +# Exit with error if there were any failures (not in WhatIf mode) +if ($failed -gt 0 -and -not $WhatIf) { Write-Host "::error::Failed to process $failed PR(s)" exit 1 } diff --git a/.github/actions/RestartStalePRChecks/action.yaml b/.github/actions/RestartStalePRChecks/action.yaml index 3c1500e23e..174ed317e1 100644 --- a/.github/actions/RestartStalePRChecks/action.yaml +++ b/.github/actions/RestartStalePRChecks/action.yaml @@ -10,6 +10,10 @@ inputs: description: Maximum number of retry attempts required: false default: '3' + whatIf: + description: If true, only performs read operations without triggering any reruns (for testing) + required: false + default: 'false' token: description: The GitHub token running the action required: false @@ -26,7 +30,8 @@ runs: GH_TOKEN: ${{ inputs.token }} GITHUB_REPOSITORY: ${{ github.repository }} run: | - ${{ github.action_path }}/action.ps1 -thresholdHours ${{ inputs.thresholdHours }} -maxRetries ${{ inputs.maxRetries }} + $whatIfSwitch = if ('${{ inputs.whatIf }}' -eq 'true') { '-WhatIf' } else { '' } + & ${{ github.action_path }}/action.ps1 -thresholdHours ${{ inputs.thresholdHours }} -maxRetries ${{ inputs.maxRetries }} $whatIfSwitch branding: icon: rotate-cw color: blue From 327b978949cfe14c61527dd64eef1d8d700fb455 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:12:33 +0000 Subject: [PATCH 14/23] Remove WhatIf from action.yaml, keep in script only Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.yaml b/.github/actions/RestartStalePRChecks/action.yaml index 174ed317e1..3c1500e23e 100644 --- a/.github/actions/RestartStalePRChecks/action.yaml +++ b/.github/actions/RestartStalePRChecks/action.yaml @@ -10,10 +10,6 @@ inputs: description: Maximum number of retry attempts required: false default: '3' - whatIf: - description: If true, only performs read operations without triggering any reruns (for testing) - required: false - default: 'false' token: description: The GitHub token running the action required: false @@ -30,8 +26,7 @@ runs: GH_TOKEN: ${{ inputs.token }} GITHUB_REPOSITORY: ${{ github.repository }} run: | - $whatIfSwitch = if ('${{ inputs.whatIf }}' -eq 'true') { '-WhatIf' } else { '' } - & ${{ github.action_path }}/action.ps1 -thresholdHours ${{ inputs.thresholdHours }} -maxRetries ${{ inputs.maxRetries }} $whatIfSwitch + ${{ github.action_path }}/action.ps1 -thresholdHours ${{ inputs.thresholdHours }} -maxRetries ${{ inputs.maxRetries }} branding: icon: rotate-cw color: blue From 05a4f0da4b63132344fbe5ec346ac0bb66b7b2bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:22:59 +0000 Subject: [PATCH 15/23] Remove redundant checkout from action Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.yaml b/.github/actions/RestartStalePRChecks/action.yaml index 3c1500e23e..eb5146a5c3 100644 --- a/.github/actions/RestartStalePRChecks/action.yaml +++ b/.github/actions/RestartStalePRChecks/action.yaml @@ -17,9 +17,6 @@ inputs: runs: using: composite steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Restart Stale PR Checks shell: pwsh env: From b9c4a69a03c585266ed8e5c0b34a12f41c3754b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 10:47:22 +0000 Subject: [PATCH 16/23] Fix Int32 overflow by using Int64 for run ID validation Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index a1fcdd8d37..9c7debed62 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -92,7 +92,7 @@ foreach ($pr in $prs) { if ($statusCheck.link -match '/runs/(\d+)') { $runId = $matches[1] # Validate run ID is a positive integer - if ([int]$runId -gt 0) { + if ([int64]$runId -gt 0) { if ($WhatIf) { Write-Host " [WhatIf] Would trigger re-run of workflow (run ID: $runId)" $restarted++ From f274fa627b44b5f7f3dd4f399633fd724cc57973 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 14:07:22 +0000 Subject: [PATCH 17/23] Add null check for GITHUB_STEP_SUMMARY to fix Path error Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.ps1 | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index 9c7debed62..79fd955ee0 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -132,15 +132,17 @@ Write-Host " ✓ Successfully restarted: $restarted workflow run(s)" Write-Host " ✗ Failed attempts: $failed" # Add GitHub Actions job summary -$summaryTitle = if ($WhatIf) { "## PR Status Check Restart Summary (WhatIf Mode)" } else { "## PR Status Check Restart Summary" } -Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $summaryTitle -Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" -if ($WhatIf) { - Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ℹ️ Running in **WhatIf mode** - no workflows were actually rerun" +if ($env:GITHUB_STEP_SUMMARY) { + $summaryTitle = if ($WhatIf) { "## PR Status Check Restart Summary (WhatIf Mode)" } else { "## PR Status Check Restart Summary" } + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $summaryTitle Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" + if ($WhatIf) { + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ℹ️ Running in **WhatIf mode** - no workflows were actually rerun" + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" + } + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully restarted: **$restarted** workflow run(s)" + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed attempts: **$failed**" } -Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully restarted: **$restarted** workflow run(s)" -Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed attempts: **$failed**" # Exit with error if there were any failures (not in WhatIf mode) if ($failed -gt 0 -and -not $WhatIf) { From 02f54ba35aeef87132f9a73bb11b0de9d8162126 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 26 Jan 2026 12:02:00 +0000 Subject: [PATCH 18/23] Clarify summary labels: failed PRs not retry attempts Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/RestartStalePRChecks/action.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index 79fd955ee0..2640a02e1d 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -129,7 +129,7 @@ foreach ($pr in $prs) { Write-Host "" Write-Host "Summary:" Write-Host " ✓ Successfully restarted: $restarted workflow run(s)" -Write-Host " ✗ Failed attempts: $failed" +Write-Host " ✗ Failed to process: $failed PR(s)" # Add GitHub Actions job summary if ($env:GITHUB_STEP_SUMMARY) { @@ -141,7 +141,7 @@ if ($env:GITHUB_STEP_SUMMARY) { Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" } Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully restarted: **$restarted** workflow run(s)" - Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed attempts: **$failed**" + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed to process: **$failed** PR(s)" } # Exit with error if there were any failures (not in WhatIf mode) From 5cda9ed733138dad9df0a8f9fa21212fe77a078a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 07:36:59 +0000 Subject: [PATCH 19/23] Change from rerun to delete workflow run + comment approach Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .../actions/RestartStalePRChecks/action.ps1 | 36 +++++++++++++------ .../actions/RestartStalePRChecks/action.yaml | 6 ++-- .github/workflows/RestartPRStatusCheck.yaml | 10 +++--- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/RestartStalePRChecks/action.ps1 index 2640a02e1d..c99e546943 100644 --- a/.github/actions/RestartStalePRChecks/action.ps1 +++ b/.github/actions/RestartStalePRChecks/action.ps1 @@ -83,9 +83,9 @@ foreach ($pr in $prs) { continue } - Write-Host " Status check is older than $thresholdHours hours, requesting rerun..." + Write-Host " Status check is older than $thresholdHours hours, deleting stale workflow run..." - # Try to rerequest the check with retries using Invoke-CommandWithRetry + # Try to delete the workflow run and add a comment with retries using Invoke-CommandWithRetry $prFailed = $false try { # Extract run ID from the check link @@ -94,14 +94,30 @@ foreach ($pr in $prs) { # Validate run ID is a positive integer if ([int64]$runId -gt 0) { if ($WhatIf) { - Write-Host " [WhatIf] Would trigger re-run of workflow (run ID: $runId)" + Write-Host " [WhatIf] Would delete workflow run (run ID: $runId) and add comment to PR #$($pr.number)" $restarted++ } else { + # Delete the workflow run Invoke-CommandWithRetry -ScriptBlock { - gh run rerun $runId -R $env:GITHUB_REPOSITORY | Out-Null + gh run delete $runId -R $env:GITHUB_REPOSITORY | Out-Null } -RetryCount $maxRetries -FirstDelay 2 -MaxWaitBetweenRetries 8 - Write-Host " ✓ Successfully triggered re-run of workflow (run ID: $runId)" + Write-Host " ✓ Successfully deleted workflow run (run ID: $runId)" + + # Add a comment to the PR with instructions + $commentBody = @" +The Pull Request Status Check for this PR was stale (older than $thresholdHours hours) and has been deleted. + +To unblock this PR and trigger a new status check, you can: +1. Push a new commit to the PR branch, or +2. Close and reopen the PR + +This will automatically trigger a new Pull Request Build workflow run. +"@ + Invoke-CommandWithRetry -ScriptBlock { + gh pr comment $pr.number --body $commentBody -R $env:GITHUB_REPOSITORY | Out-Null + } -RetryCount $maxRetries -FirstDelay 2 -MaxWaitBetweenRetries 8 + Write-Host " ✓ Added comment to PR #$($pr.number) with instructions" $restarted++ } } @@ -116,7 +132,7 @@ foreach ($pr in $prs) { } } catch { - Write-Host " ✗ Failed to restart workflow: $_" + Write-Host " ✗ Failed to delete workflow run or add comment: $_" $prFailed = $true } @@ -128,19 +144,19 @@ foreach ($pr in $prs) { Write-Host "" Write-Host "Summary:" -Write-Host " ✓ Successfully restarted: $restarted workflow run(s)" +Write-Host " ✓ Successfully processed: $restarted PR(s)" Write-Host " ✗ Failed to process: $failed PR(s)" # Add GitHub Actions job summary if ($env:GITHUB_STEP_SUMMARY) { - $summaryTitle = if ($WhatIf) { "## PR Status Check Restart Summary (WhatIf Mode)" } else { "## PR Status Check Restart Summary" } + $summaryTitle = if ($WhatIf) { "## Stale PR Status Check Cleanup Summary (WhatIf Mode)" } else { "## Stale PR Status Check Cleanup Summary" } Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $summaryTitle Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" if ($WhatIf) { - Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ℹ️ Running in **WhatIf mode** - no workflows were actually rerun" + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ℹ️ Running in **WhatIf mode** - no workflow runs were deleted" Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" } - Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully restarted: **$restarted** workflow run(s)" + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully processed: **$restarted** PR(s) (deleted stale workflow runs and added comments)" Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed to process: **$failed** PR(s)" } diff --git a/.github/actions/RestartStalePRChecks/action.yaml b/.github/actions/RestartStalePRChecks/action.yaml index eb5146a5c3..b3265528e8 100644 --- a/.github/actions/RestartStalePRChecks/action.yaml +++ b/.github/actions/RestartStalePRChecks/action.yaml @@ -1,6 +1,6 @@ -name: Restart Stale PR Checks +name: Clean Up Stale PR Checks author: Microsoft Corporation -description: Restart stale PR status checks that are older than a specified threshold +description: Delete stale PR status check workflow runs and add comments with instructions to unblock PRs inputs: thresholdHours: description: Threshold in hours for considering a check stale @@ -17,7 +17,7 @@ inputs: runs: using: composite steps: - - name: Restart Stale PR Checks + - name: Clean Up Stale PR Checks shell: pwsh env: GH_TOKEN: ${{ inputs.token }} diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/RestartPRStatusCheck.yaml index c0979b1a7c..89ea7faf3d 100644 --- a/.github/workflows/RestartPRStatusCheck.yaml +++ b/.github/workflows/RestartPRStatusCheck.yaml @@ -1,4 +1,4 @@ -name: 'Restart Pull Request Status Check' +name: 'Clean Up Stale PR Status Checks' on: schedule: @@ -9,21 +9,21 @@ permissions: actions: write checks: read contents: read - pull-requests: read + pull-requests: write defaults: run: shell: pwsh jobs: - RestartStatusChecks: + CleanUpStatusChecks: runs-on: ubuntu-latest - name: Restart Stale PR Status Checks + name: Clean Up Stale PR Status Checks steps: - name: Checkout uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Restart Stale PR Status Checks + - name: Clean Up Stale PR Status Checks uses: ./.github/actions/RestartStalePRChecks with: token: ${{ github.token }} From ea32524470ac784ed98eb89c3dede665f2a56641 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 08:28:20 +0000 Subject: [PATCH 20/23] Rename files to match new "Clean Up" approach Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .../{RestartStalePRChecks => CleanUpStalePRChecks}/action.ps1 | 0 .../{RestartStalePRChecks => CleanUpStalePRChecks}/action.yaml | 0 .../{RestartPRStatusCheck.yaml => CleanUpStalePRChecks.yaml} | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename .github/actions/{RestartStalePRChecks => CleanUpStalePRChecks}/action.ps1 (100%) rename .github/actions/{RestartStalePRChecks => CleanUpStalePRChecks}/action.yaml (100%) rename .github/workflows/{RestartPRStatusCheck.yaml => CleanUpStalePRChecks.yaml} (91%) diff --git a/.github/actions/RestartStalePRChecks/action.ps1 b/.github/actions/CleanUpStalePRChecks/action.ps1 similarity index 100% rename from .github/actions/RestartStalePRChecks/action.ps1 rename to .github/actions/CleanUpStalePRChecks/action.ps1 diff --git a/.github/actions/RestartStalePRChecks/action.yaml b/.github/actions/CleanUpStalePRChecks/action.yaml similarity index 100% rename from .github/actions/RestartStalePRChecks/action.yaml rename to .github/actions/CleanUpStalePRChecks/action.yaml diff --git a/.github/workflows/RestartPRStatusCheck.yaml b/.github/workflows/CleanUpStalePRChecks.yaml similarity index 91% rename from .github/workflows/RestartPRStatusCheck.yaml rename to .github/workflows/CleanUpStalePRChecks.yaml index 89ea7faf3d..5d47d0f659 100644 --- a/.github/workflows/RestartPRStatusCheck.yaml +++ b/.github/workflows/CleanUpStalePRChecks.yaml @@ -24,6 +24,6 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Clean Up Stale PR Status Checks - uses: ./.github/actions/RestartStalePRChecks + uses: ./.github/actions/CleanUpStalePRChecks with: token: ${{ github.token }} From 1e1f36f51a4779a3e87d6c09ea5d6a2167562b84 Mon Sep 17 00:00:00 2001 From: Maria Zhelezova <43066499+mazhelez@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:32:12 +0100 Subject: [PATCH 21/23] Enhance comment for deleted stale PR status checks Updated the comment body for stale PR status checks to provide clearer instructions and reasoning for deletion. --- .../actions/CleanUpStalePRChecks/action.ps1 | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/actions/CleanUpStalePRChecks/action.ps1 b/.github/actions/CleanUpStalePRChecks/action.ps1 index c99e546943..eaa1576ff3 100644 --- a/.github/actions/CleanUpStalePRChecks/action.ps1 +++ b/.github/actions/CleanUpStalePRChecks/action.ps1 @@ -106,13 +106,22 @@ foreach ($pr in $prs) { # Add a comment to the PR with instructions $commentBody = @" -The Pull Request Status Check for this PR was stale (older than $thresholdHours hours) and has been deleted. +## ⚠️ Stale Status Check Deleted -To unblock this PR and trigger a new status check, you can: -1. Push a new commit to the PR branch, or -2. Close and reopen the PR +The **Pull Request Build** workflow run for this PR was older than **$thresholdHours hours** and has been deleted. -This will automatically trigger a new Pull Request Build workflow run. +### 📋 Why was it deleted? + +Status checks that are too old may no longer reflect the current state of the target branch. To ensure this PR is validated against the latest code and passes up-to-date checks, a fresh build is required. + +--- + +### 🔄 How to trigger a new status check: + +1. 📤 **Push a new commit** to the PR branch, or +2. 🔁 **Close and reopen** the PR + +This will automatically trigger a new **Pull Request Build** workflow run. "@ Invoke-CommandWithRetry -ScriptBlock { gh pr comment $pr.number --body $commentBody -R $env:GITHUB_REPOSITORY | Out-Null From 5d20075b637d0f949d85fb7cb29c0e1d700bb137 Mon Sep 17 00:00:00 2001 From: Maria Zhelezova <43066499+mazhelez@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:53:53 +0100 Subject: [PATCH 22/23] Update .github/actions/CleanUpStalePRChecks/action.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/actions/CleanUpStalePRChecks/action.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/actions/CleanUpStalePRChecks/action.ps1 b/.github/actions/CleanUpStalePRChecks/action.ps1 index eaa1576ff3..c99c82593c 100644 --- a/.github/actions/CleanUpStalePRChecks/action.ps1 +++ b/.github/actions/CleanUpStalePRChecks/action.ps1 @@ -162,10 +162,15 @@ if ($env:GITHUB_STEP_SUMMARY) { Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value $summaryTitle Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" if ($WhatIf) { - Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ℹ️ Running in **WhatIf mode** - no workflow runs were deleted" + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ℹ️ Running in **WhatIf mode** - no workflow runs were deleted and no comments were added" Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" } - Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully processed: **$restarted** PR(s) (deleted stale workflow runs and added comments)" + if ($WhatIf) { + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully processed: **$restarted** PR(s) (WhatIf mode: no workflow runs were deleted or comments added)" + } + else { + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully processed: **$restarted** PR(s) (deleted stale workflow runs and added comments)" + } Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✗ Failed to process: **$failed** PR(s)" } From e6b186a15d5bf116b2ff88b557c2ec849c84cffc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 14:56:22 +0000 Subject: [PATCH 23/23] Fix cross-platform path and update WhatIf messaging Co-authored-by: mazhelez <43066499+mazhelez@users.noreply.github.com> --- .github/actions/CleanUpStalePRChecks/action.ps1 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/actions/CleanUpStalePRChecks/action.ps1 b/.github/actions/CleanUpStalePRChecks/action.ps1 index c99c82593c..3278709600 100644 --- a/.github/actions/CleanUpStalePRChecks/action.ps1 +++ b/.github/actions/CleanUpStalePRChecks/action.ps1 @@ -3,7 +3,7 @@ param ( [int] $thresholdHours = 72, [Parameter(Mandatory = $false, HelpMessage="Maximum number of retry attempts")] [int] $maxRetries = 3, - [Parameter(Mandatory = $false, HelpMessage="If specified, only performs read operations without triggering any reruns")] + [Parameter(Mandatory = $false, HelpMessage="If specified, only performs read operations without deleting workflow runs or adding PR comments")] [switch] $WhatIf ) @@ -12,10 +12,10 @@ $ProgressPreference = "SilentlyContinue" Set-StrictMode -Version 2.0 # Import EnlistmentHelperFunctions module -Import-Module "$PSScriptRoot\..\..\..\build\scripts\EnlistmentHelperFunctions.psm1" -DisableNameChecking +Import-Module "$PSScriptRoot/../../../build/scripts/EnlistmentHelperFunctions.psm1" -DisableNameChecking if ($WhatIf) { - Write-Host "::notice::Running in WhatIf mode - no workflows will be rerun" + Write-Host "::notice::Running in WhatIf mode - no workflow runs will be deleted and no comments will be added" } Write-Host "Fetching open pull requests..." @@ -164,9 +164,7 @@ if ($env:GITHUB_STEP_SUMMARY) { if ($WhatIf) { Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ℹ️ Running in **WhatIf mode** - no workflow runs were deleted and no comments were added" Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "" - } - if ($WhatIf) { - Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully processed: **$restarted** PR(s) (WhatIf mode: no workflow runs were deleted or comments added)" + Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully processed: **$restarted** PR(s) (would have deleted stale workflow runs and added comments)" } else { Add-Content -Path $env:GITHUB_STEP_SUMMARY -Value "- ✓ Successfully processed: **$restarted** PR(s) (deleted stale workflow runs and added comments)"