Modules/AzureDevOpsDsc.Common/Resources/Functions/Public/AzDoPipeline/Set-AzDoPipeline.ps1
|
<#
.SYNOPSIS Updates an Azure DevOps YAML pipeline. .DESCRIPTION Updates the pipeline's name, folder, YAML path, default branch and repository (Azure Repos, or an external repository reached through a service connection), then writes any 'Variables' supplied. The Pipelines API has no update verb, so both steps write the underlying build definition back through 'Set-DevOpsPipeline' and 'Set-DevOpsPipelineVariables'. A failed API call is thrown rather than written: 'Write-Error' inside a class-based DSC method never reaches the Invoke-DscResource caller, so 'Set()' would report success while 'Test()' kept failing. .PARAMETER ProjectName The Azure DevOps project name. .PARAMETER PipelineName The name of the pipeline. .PARAMETER RepositoryName The repository that contains the YAML file. An Azure Repos repository name, or 'owner/repo' for GitHub/GitHub Enterprise/Bitbucket. .PARAMETER YamlPath The path to the YAML pipeline definition file. .PARAMETER FolderPath The folder path under which the pipeline is organised. .PARAMETER DefaultBranch The default branch for the pipeline. .PARAMETER RepositoryType The type of repository backing the pipeline. 'TfsGit', 'GitHub', 'GitHubEnterprise' or 'Bitbucket'. .PARAMETER ServiceConnectionName The service connection used to reach the repository. Required when 'RepositoryType' is not 'TfsGit'. .PARAMETER Variables Pipeline variables to manage, as an array of hashtables shaped '@{ Name; Value; IsSecret; AllowOverride }'. .PARAMETER LookupResult The lookup result supplied by the DSC base class. .PARAMETER Ensure The desired state, supplied by the DSC base class. .PARAMETER Force Forces the operation, supplied by the DSC base class. .EXAMPLE Set-AzDoPipeline -ProjectName 'Contoso' -PipelineName 'CI' -RepositoryName 'Contoso' -YamlPath 'azure-pipelines.yml' #> Function Set-AzDoPipeline { [CmdletBinding()] param ( [Parameter(Mandatory = $true)][string]$ProjectName, [Parameter(Mandatory = $true)][string]$PipelineName, [Parameter(Mandatory = $true)][string]$RepositoryName, [Parameter(Mandatory = $true)][string]$YamlPath, [Parameter()][string]$FolderPath = '\', [Parameter()][string]$DefaultBranch = 'main', [Parameter()][ValidateSet('TfsGit', 'GitHub', 'GitHubEnterprise', 'Bitbucket')][string]$RepositoryType = 'TfsGit', [Parameter()][string]$ServiceConnectionName, [Parameter()][Hashtable[]]$Variables, [Parameter()][HashTable]$LookupResult, [Parameter()][Ensure]$Ensure, [Parameter()][System.Management.Automation.SwitchParameter]$Force ) Write-Verbose "[Set-AzDoPipeline] Updating pipeline '$PipelineName'." # 'Get' returning 'Error' still routes here (see AzDevOpsDscResourceBase.GetDscRequiredAction()), # so the same guard that 'Get-AzDoPipeline' applies has to be repeated here. if ($RepositoryType -ne 'TfsGit' -and [String]::IsNullOrWhiteSpace($ServiceConnectionName)) { Write-Error "[Set-AzDoPipeline] 'ServiceConnectionName' is required when 'RepositoryType' is '$RepositoryType'." return } $pipeline = Get-CacheItem -Key ('{0}\{1}' -f $ProjectName, $PipelineName) -Type 'LivePipelines' if (-not $pipeline) { Write-Error "[Set-AzDoPipeline] Pipeline '$PipelineName' not found in cache." return } $OrgName = Get-AzDoOrganizationName $ApiUri = 'https://dev.azure.com/{0}/' -f $OrgName $repositoryId = $null $serviceConnectionId = $null $repository = $null $connection = $null if ($RepositoryType -eq 'TfsGit') { $repository = Get-CacheItem -Key ('{0}\{1}' -f $ProjectName, $RepositoryName) -Type 'LiveRepositories' if (-not $repository) { Write-Verbose "[Set-AzDoPipeline] Repository '$RepositoryName' not in cache — falling back to live API lookup." $allRepos = List-DevOpsGitRepository -OrganizationName $OrgName -ProjectName $ProjectName $repository = $allRepos | Where-Object { $_.name -eq $RepositoryName } | Select-Object -First 1 } $repositoryId = if ($repository) { $repository.id } else { $null } } else { $connection = Resolve-AzDoServiceConnection -ProjectName $ProjectName -ConnectionName $ServiceConnectionName if (-not $connection) { Write-Error "[Set-AzDoPipeline] Service connection '$ServiceConnectionName' not found in project '$ProjectName'." return } $serviceConnectionId = $connection.id } # The build definition API takes the resource-side repository type names as they are. $params = @{ ApiUri = $ApiUri ProjectName = $ProjectName PipelineId = $pipeline.id PipelineName = $PipelineName FolderPath = $FolderPath YamlFilePath = $YamlPath RepositoryId = $repositoryId RepositoryName = $RepositoryName RepositoryType = $RepositoryType RepositoryUrl = Get-AzDoPipelineRepositoryUrl -RepositoryType $RepositoryType -RepositoryName $RepositoryName -Repository $repository -ServiceConnection $connection ServiceConnectionId = $serviceConnectionId DefaultBranch = 'refs/heads/{0}' -f $DefaultBranch } $value = Set-DevOpsPipeline @params if ($null -eq $value) { Write-Error "[Set-AzDoPipeline] Set-DevOpsPipeline returned null. Check authentication token and organization settings." return } # Cached in the shape the Pipelines API lists, which is what 'Get-AzDoPipeline' and the # pipeline permission resources read. Cached before the variables are written so a failure # there does not lose the update that did go through. $cachedPipeline = [PSCustomObject]@{ id = $pipeline.id revision = $value.revision name = $PipelineName folder = $FolderPath url = $pipeline.url } Add-CacheItem -Key ('{0}\{1}' -f $ProjectName, $PipelineName) -Value $cachedPipeline -Type 'LivePipelines' Export-CacheObject -CacheType 'LivePipelines' -Content $AzDoLivePipelines Refresh-CacheObject -CacheType 'LivePipelines' if ($Variables -and $Variables.Count -gt 0) { Write-Verbose "[Set-AzDoPipeline] Writing $($Variables.Count) variable(s) onto pipeline '$PipelineName'." Set-DevOpsPipelineVariables -ApiUri $ApiUri -ProjectName $ProjectName -DefinitionId $pipeline.id -Variables $Variables | Out-Null } Write-Verbose "[Set-AzDoPipeline] Pipeline '$PipelineName' updated." } |