utilities/tools/Invoke-WorkflowsFailedJobsReRun.ps1 (202 lines of code) (raw):
#region helper functions
<#
.SYNOPSIS
Invoke the re-run for a given set of workflow runs.
.DESCRIPTION
Invoke the re-run for a given set of workflow runs.
.PARAMETER RestInputObject
Mandatory. The REST parameters to use for the re-run. Must contain the 'RepositoryOwner' and 'RepositoryName' keys and may contain the 'PersonalAccessToken' key.
.PARAMETER RunsToReTrigger
Manadatory. The workflow runs to re-trigger.
.PARAMETER TotalNumberOfWorkflows
Mandatory. The total number of workflows to re-trigger.
.EXAMPLE
Invoke-ReRun -RestInputObject @{ RepositoryOwner = 'Azure'; RepositoryName = 'bicep-registry-modules' } -RunsToReTrigger @(@{ id = 123; name = 'keyvaultworkflow'}) -TotalNumberOfWorkflows 123
Re-run the failed jobs for all provided runs in the repository [Azure/bicep-registry-modules].
#>
function Invoke-ReRun {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory)]
[hashtable] $RestInputObject,
[Parameter(Mandatory)]
[object[]] $RunsToReTrigger,
[Parameter(Mandatory)]
[int] $TotalNumberOfWorkflows
)
$totalCount = $RunsToReTrigger.Count
$currentCount = 1
Write-Verbose ('Runs to re-run failed jobs for [{0}/{1}]' -f $RunsToReTrigger.Count, $TotalNumberOfWorkflows) -Verbose
foreach ($run in $RunsToReTrigger) {
$percentageComplete = [math]::Round(($currentCount / $totalCount) * 100)
Write-Progress -Activity ('Re-running failed jobs for workflow [{0}]' -f $run.name) -Status "$percentageComplete% complete" -PercentComplete $percentageComplete
if ($PSCmdlet.ShouldProcess(("Re-run of failed jobs for GitHub workflow [{0}] for branch [$TargetBranch]" -f $run.name), 'Invoke')) {
$null = Invoke-GitHubWorkflowRunFailedJobsReRun @RestInputObject -RunId $run.id
}
$currentCount++
}
}
<#
.SYNOPSIS
Invoke the 'Rerun failed jobs' action for a given GitHub workflow run.
.DESCRIPTION
Invoke the 'Rerun failed jobs' action for a given GitHub workflow run.
.PARAMETER PersonalAccessToken
Optional. The PAT to use to interact with either GitHub. If not provided, the script will use the GitHub CLI to authenticate.
.PARAMETER RepositoryOwner
Optional. The GitHub organization to run the workfows in.
.PARAMETER RepositoryName
Optional. The GitHub repository to run the workfows in.
.PARAMETER RunId
Mandatory. The ID of the run to re-run the failed jobs for.
.EXAMPLE
Invoke-GitHubWorkflowRunFailedJobsReRun -RepositoryOwner 'Azure' -RepositoryName 'bicep-registry-modules' -RunId '447791597'
Re-run the failed jobs for the GitHub workflow run with ID '447791597' in the repository [Azure/bicep-registry-modules].
#>
function Invoke-GitHubWorkflowRunFailedJobsReRun {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[string] $PersonalAccessToken,
[Parameter(Mandatory = $true)]
[string] $RepositoryOwner,
[Parameter(Mandatory = $true)]
[string] $RepositoryName,
[Parameter(Mandatory = $true)]
[string] $RunId
)
$queryUrl = "/repos/$RepositoryOwner/$RepositoryName/actions/runs/$RunId/rerun-failed-jobs"
if ($PersonalAccessToken) {
# Using PAT
$requestInputObject = @{
Method = 'POST'
Uri = "https://api.github.com$queryUrl"
Headers = @{
Authorization = "Bearer $PersonalAccessToken"
}
}
$response = Invoke-RestMethod @requestInputObject
} else {
# Using GH API instead of 'gh workflow list' to get all results instead of just the first few
$requestInputObject = @(
'--method', 'POST',
'-H', 'Accept: application/vnd.github+json',
'-H', 'X-GitHub-Api-Version: 2022-11-28',
$queryUrl
)
$response = (gh api @requestInputObject | ConvertFrom-Json)
}
if ("$response") {
# If successfull, the response will be an empty custom object. Must be casted to string
Write-Error "Request failed. Response: [$response]"
return $false
}
return $true
}
#endregion
<#
.SYNOPSIS
Re-runs all failed jobs across all workflows for a given GitHub repository.
.DESCRIPTION
Re-runs all failed jobs across all workflows for a given GitHub repository.
By default, pipelines are filtered to AVM module pipelines & the main branch.
Currently running workflows are excluded.
.PARAMETER PersonalAccessToken
Optional. The PAT to use to interact with either GitHub. If not provided, the script will use the GitHub CLI to authenticate.
.PARAMETER TargetBranch
Optional. The branch to run the pipelines for (e.g. `main`). Defaults to 'main'.
.PARAMETER PipelineFilter
Optional. The pipeline files to filter down to (regex).
.PARAMETER RepositoryOwner
Optional. The GitHub organization to run the workfows in.
.PARAMETER RepositoryName
Optional. The GitHub repository to run the workfows in.
.PARAMETER RepoRoot
Optional. Path to the root of the repository.
.EXAMPLE
Invoke-WorkflowsFailedJobsReRun -PersonalAccessToken '<Placeholder>' -TargetBranch 'feature/branch' -PipelineFilter 'avm\.(?:res|ptn|utl)'
Run the failed jobs for all GitHub workflows that match 'avm\.(?:res|ptn|utl)' using branch 'feature/branch'.
.EXAMPLE
Invoke-WorkflowsFailedJobsReRun -PersonalAccessToken '<Placeholder>' -TargetBranch 'feature/branch' -PipelineFilter 'avm\.(?:res|ptn|utl)' -WhatIf
Only simulate the triggering of the failed jobs for all failed GitHub workflows that match 'avm\.(?:res|ptn|utl)' using branch 'feature/branch'.
.EXAMPLE
Invoke-WorkflowsFailedJobsReRun -PersonalAccessToken '<Placeholder>' -RepositoryOwner 'MyFork'
Only simulate the triggering of the failed jobs of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res.res|ptn|utl', using the main branch & PAT.
.EXAMPLE
Invoke-WorkflowsFailedJobsReRun -RepositoryOwner 'MyFork'
Only simulate the triggering of the failed jobs of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res.res|ptn|utl', using the main branch & your current GH CLI login.
#>
function Invoke-WorkflowsFailedJobsReRun {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory = $false)]
[string] $PersonalAccessToken,
[Parameter(Mandatory = $false)]
[string] $TargetBranch = 'main',
[Parameter(Mandatory = $false)]
[string] $PipelineFilter = 'avm\.(?:res|ptn|utl)',
[Parameter(Mandatory = $false)]
[string] $RepositoryOwner = 'Azure',
[Parameter(Mandatory = $false)]
[string] $RepositoryName = 'bicep-registry-modules',
[Parameter(Mandatory = $false)]
[string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.FullName
)
# Load helper functions
. (Join-Path $repoRoot 'utilities' 'pipelines' 'platform' 'helper' 'Get-GitHubModuleWorkflowList.ps1')
. (Join-Path $repoRoot 'utilities' 'pipelines' 'platform' 'helper' 'Get-GitHubModuleWorkflowLatestRun.ps1')
$baseInputObject = @{
RepositoryOwner = $RepositoryOwner
RepositoryName = $RepositoryName
}
if ($PersonalAccessToken) {
$baseInputObject['PersonalAccessToken'] = @{
PersonalAccessToken = $PersonalAccessToken
}
}
#####################################
# Get all workflows for branch #
#####################################
Write-Verbose 'Fetching current GitHub workflows' -Verbose
$workflows = Get-GitHubModuleWorkflowList @baseInputObject -Filter $PipelineFilter
Write-Verbose ('Fetched [{0}] workflows' -f $workflows.Count) -Verbose
######################################################
# Analyze latest run of each workflow for branch #
######################################################
$totalCount = $workflows.Count
$currentCount = 1
$runsToReTrigger = [System.Collections.ArrayList]@()
foreach ($workflow in $workflows) {
$percentageComplete = [math]::Round(($currentCount / $totalCount) * 100)
Write-Progress -Activity ('Analyzing workflow [{0}]' -f $workflow.name) -Status "$percentageComplete% complete" -PercentComplete $percentageComplete
# Get relevant runs
$latestBranchRun = Get-GitHubModuleWorkflowLatestRun @baseInputObject -WorkflowId $workflow.id -TargetBranch $TargetBranch
if ($latestBranchRun.status -eq 'completed' -and $latestBranchRun.conclusion -eq 'failure') {
$runsToReTrigger += $latestBranchRun
}
$currentCount++
}
##############################
# Re-trigger failed runs #
##############################
$reRunInputObject = @{
RestInputObject = $baseInputObject
RunsToReTrigger = $runsToReTrigger
TotalNumberOfWorkflows = $workflows.Count
}
$null = Invoke-ReRun @reRunInputObject -WhatIf:$WhatIfPreference
# Enable the user to execute the invocation if the whatif looked good
if ($WhatIfPreference) {
do {
$userInput = Read-Host -Prompt 'Should apply (y/n)?'
}
while ($userInput -notin @('y', 'n'))
switch ($userInput) {
'y' {
$null = Invoke-ReRun @reRunInputObject -WhatIf:$false
}
'n' { return }
}
}
Write-Verbose 'Re-triggerung complete' -Verbose
}