utilities/tools/Invoke-WorkflowsForBranch.ps1 (202 lines of code) (raw):

#region helper functions <# .SYNOPSIS Invoke a given GitHub workflow .DESCRIPTION Invoke a given GitHub workflow .PARAMETER PersonalAccessToken Optional. The PAT to use to interact with either GitHub / Azure DevOps. If not provided, the script will use the GitHub CLI to authenticate. .PARAMETER RepositoryOwner Mandatory. The repository's organization. .PARAMETER RepositoryName Mandatory. The name of the repository to trigger the workflows in. .PARAMETER WorkflowFileName Mandatory. The name of the workflow to trigger .PARAMETER TargetBranch Optional. The branch to trigger the pipeline for. .PARAMETER WorkflowInputs Optional. Input parameters to pass into the pipeline. Must match the names of the runtime parameters in the yaml file(s) .EXAMPLE Invoke-GitHubWorkflow -PersonalAccessToken '<Placeholder>' -RepositoryOwner 'Azure' -RepositoryName 'bicep-registry-modules' -WorkflowFileName 'avm.res.analysis-services.servers.yml' -TargetBranch 'main' -WorkflowInputs @{ staticValidation = 'true'; deploymentValidation = 'true'; removeDeployment = 'true' } Trigger the workflow 'avm.res.analysis-services.servers.yml' with branch 'main' in repository 'Azure/bicep-registry-modules'. #> function Invoke-GitHubWorkflow { [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory = $false)] [string] $PersonalAccessToken, [Parameter(Mandatory = $true)] [string] $RepositoryOwner, [Parameter(Mandatory = $true)] [string] $RepositoryName, [Parameter(Mandatory = $false)] [hashtable] $WorkflowInputs = @{}, [Parameter(Mandatory = $true)] [string] $WorkflowFileName, [Parameter(Mandatory = $false)] [string] $TargetBranch = 'main' ) $triggerUrl = "/repos/$RepositoryOwner/$RepositoryName/actions/workflows/$WorkflowFileName/dispatches" if ($PersonalAccessToken) { # Using PAT $requestInputObject = @{ Method = 'POST' Uri = "https://api.github.com$triggerUrl" Headers = @{ Authorization = "Bearer $PersonalAccessToken" } Body = @{ ref = $TargetBranch inputs = $WorkflowInputs } | ConvertTo-Json } if ($PSCmdlet.ShouldProcess("GitHub workflow [$WorkflowFileName] for branch [$TargetBranch]", 'Invoke')) { try { $response = Invoke-RestMethod @requestInputObject -Verbose:$false } catch { Write-Error ("Request failed for [$WorkflowFileName]. Response: [{0}]" -f $_.ErrorDetails) return $false } if ($response) { Write-Error "Request failed. Response: [$response]" return $false } } } else { # Using GH API instead o $requestInputObject = @( '--method', 'POST', '-H', 'Accept: application/vnd.github+json', '-H', 'X-GitHub-Api-Version: 2022-11-28', '-f', "ref=$TargetBranch", $triggerUrl ) # Adding inputs foreach ($key in $WorkflowInputs.Keys) { $requestInputObject += @( '-f', ('inputs[{0}]={1}' -f $key, $WorkflowInputs[$key]) ) } if ($PSCmdlet.ShouldProcess("GitHub workflow [$WorkflowFileName] for branch [$TargetBranch]", 'Invoke')) { $response = (gh api @requestInputObject | ConvertFrom-Json) } if ($response) { Write-Error "Request failed. Response: [$response]" return $false } } return $true } #endregion <# .SYNOPSIS Trigger all pipelines for GitHub .DESCRIPTION Trigger all workflows for the given GitHub repository. By default, pipelines are filtered to AVM module pipelines. .PARAMETER PersonalAccessToken Optional. The PAT to use to interact with either GitHub / Azure DevOps. 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 currently checked-out branch. .PARAMETER PipelineFilter Optional. The pipeline files to filter down to (regex). .PARAMETER SkipPipelineBadges Optional. Specify to disable the output of generated pipeline status badges for the given pipeline configuration. .PARAMETER RepositoryOwner Optional. The GitHub organization to run the workfows in. .PARAMETER RepositoryName Optional. The GitHub repository to run the workfows in. .PARAMETER WorkflowInputs Optional. The inputs to pass into the workflows. Defaults to only run static validation. .PARAMETER InvokeForDiff Optional. Trigger workflows only for those who's module files have changed (based on diff of branch to main) .EXAMPLE Invoke-WorkflowsForBranch -PersonalAccessToken '<Placeholder>' -TargetBranch 'feature/branch' -PipelineFilter 'avm\.(?:res|ptn|utl)' -WorkflowInputs @{ staticValidation = 'true'; deploymentValidation = 'true'; removeDeployment = 'true' } Run all GitHub workflows that match 'avm\.(?:res|ptn|utl)' using branch 'feature/branch'. Also returns all GitHub status badges. .EXAMPLE Invoke-WorkflowsForBranch -PersonalAccessToken '<Placeholder>' -TargetBranch 'feature/branch' -PipelineFilter 'avm\.(?:res|ptn|utl)' -WorkflowInputs @{ staticValidation = 'true'; deploymentValidation = 'true'; removeDeployment = 'true' } -WhatIf Only simulate the triggering of all GitHub workflows that match 'avm\.(?:res|ptn|utl)' using branch 'feature/branch'. Hence ONLY returns all GitHub status badges. .EXAMPLE Invoke-WorkflowsForBranch -PersonalAccessToken '<Placeholder>' -RepositoryOwner 'MyFork' Only simulate the triggering of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res.res|ptn|utl', using the current locally checked out branch. Also returns all GitHub status badges. .EXAMPLE Invoke-WorkflowsForBranch -RepositoryOwner 'MyFork' Only simulate the triggering of all GitHub workflows of project [MyFork/bicep-registry-modules] that start with'avm.res|ptn|utl.', using the current locally checked out branch and the GitHub CLI. Also returns all GitHub status badges. #> function Invoke-WorkflowsForBranch { [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory = $false)] [string] $PersonalAccessToken, [Parameter(Mandatory = $false)] [string] $TargetBranch = (git branch --show-current), [Parameter(Mandatory = $false)] [string] $PipelineFilter = 'avm\.(?:res|ptn|utl)', [Parameter(Mandatory = $false)] [switch] $InvokeForDiff, [Parameter(Mandatory = $false)] [switch] $SkipPipelineBadges, [Parameter(Mandatory = $false)] [string] $RepositoryOwner = 'Azure', [Parameter(Mandatory = $false)] [string] $RepositoryName = 'bicep-registry-modules', [Parameter(Mandatory = $false)] [hashtable] $WorkflowInputs = @{ staticValidation = 'true' deploymentValidation = 'false' removeDeployment = 'false' }, [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') $baseInputObject = @{ RepositoryOwner = $RepositoryOwner RepositoryName = $RepositoryName } if ($PersonalAccessToken) { $baseInputObject['PersonalAccessToken'] = @{ PersonalAccessToken = $PersonalAccessToken } } Write-Verbose 'Fetching current GitHub workflows' -Verbose $workflows = Get-GitHubModuleWorkflowList @baseInputObject -Filter $PipelineFilter Write-Verbose ('Fetched [{0}] workflows' -f $workflows.Count) -Verbose if ($InvokeForDiff) { # Load used function . (Join-Path $RepoRoot 'utilities' 'pipelines' 'sharedScripts' 'Get-PipelineFileName.ps1') # Get diff $diff = git diff 'main' --name-only # Identify pipeline names $pipelineNames = [System.Collections.ArrayList]@() $pipelineNames = $diff | ForEach-Object { $folderPath = Split-Path $_ -Parent $pipelineFileName = Get-PipelineFileName -ResourceIdentifier $folderPath if ($pipelineFileName -match $PipelineFilter) { $pipelineFileName } } | Select-Object -Unique # Filter workflows $workflows = $workflows | Where-Object { $pipelineNames -contains (Split-Path $_.path -Leaf) } Write-Verbose ("As per 'diff', filtered workflows down to [{0}]" -f $workflows.Count) } $gitHubWorkflowBadges = [System.Collections.ArrayList]@() Write-Verbose "Triggering GitHub workflows for branch [$TargetBranch]" -Verbose foreach ($workflow in $workflows) { $workflowFileName = Split-Path $Workflow.path -Leaf if ($PSCmdlet.ShouldProcess("GitHub workflow [$workflowFileName] for branch [$TargetBranch]", 'Invoke')) { $null = Invoke-GitHubWorkflow @baseInputObject -TargetBranch $TargetBranch -WorkflowFileName $workflowFileName -WorkflowInputs $WorkflowInputs } # Generate pipeline badges if (-not $SkipPipelineBadges) { $encodedBranch = [uri]::EscapeDataString($TargetBranch) $workflowUrl = "https://github.com/$RepositoryOwner/$RepositoryName/actions/workflows/$workflowFileName" $gitHubWorkflowBadges += "[![$($workflow.name)]($workflowUrl/badge.svg?branch=$encodedBranch&event=workflow_dispatch)]($workflowUrl)" } } if ($gitHubWorkflowBadges.Count -gt 0) { Write-Verbose 'GitHub Workflow Badges' -Verbose Write-Verbose '======================' -Verbose Write-Verbose ($gitHubWorkflowBadges | Sort-Object -Culture 'en-US' | Out-String) -Verbose } }