在 PowerShell 中使用 Azure DevOps REST API 更新构建定义

Update build definition using Azure DevOps REST API in PowerShell

我正在尝试通过 PowerShell 脚本使用 REST API 在 Azure DevOps 中更新我的构建定义...

$header = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($personalAccessToken)"))}
$definitions = Invoke-RestMethod -Uri "https://devops.domain.com/Collection/Project/_apis/build/definitions" -Method GET -Header $header
$branchNames = 'master', 'feature'

ForEach ($definition in $definitions.value) {
    $definition | Add-Member -NotePropertyName triggers -NotePropertyValue (@{ triggerType = 'continuousIntegration'; branchFilters = $branchNames | % {"+refs/heads/$_/*"} }) -Force

    $body = $definition | ConvertTo-Json
    Write-Host $body

    Invoke-RestMethod -Uri "https://devops.domain.com/Collection/Project/_apis/build/definitions/$($definition.id)?api-version=5.0" -Method PUT -ContentType application/json -Body $body -Header $header
}

Azure DevOps documentation 中还不是特别清楚我应该如何使用此方法更新构建定义,但上述结果导致以下错误:

Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: definition.Repository","typeName":"System.ArgumentNullException, mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}

这是我想知道我是否在咆哮错误的树,因为这肯定更简单(我在 SO here 上找到了一个用于创建新构建定义的简单解决方案)。事实上,我只想更新触发器分支过滤器。

如何使用 PowerShell 和 REST 实现此目的 API?

triggers是数组所以你不能只编辑它,你需要编辑triggers[0],同样的事情是branchFilters,你需要编辑branchFilters[0]。此外,您无需触摸 triggerType.

以上所有假设构建中已经有一个触发器并且您想对其进行编辑,而不是添加新的触发器部分。

branchFilters数组中还有一个棘手的事情,如果你只有一个分支(例如master)并且你想添加另一个分支你需要将它添加到数组中而不仅仅是编辑 branchFilters[0] 值。

最后应该修复的是分支值,它应该是 +refs/heads/branchName 而不仅仅是分支名称。

所以,我有一个带有 test 分支触发器的管道,我成功地使用此脚本将触发器编辑为 masterfeature/*

# I get only one definition and update him, not iterate all my definitions
$definition = Invoke-RestMethod -Uri $url -Method Get

# Change the branch trigger from "test" to "master"
$definition.triggers[0].branchFilters[0] = "+refs/heads/master"

# Add another branch trigger - "feature/*"
$definition.triggers[0].branchFilters[0] += "+refs/heads/feature/*"

$body = $definition | ConvertTo-Json -Depth 10
Write-Host $body

Invoke-RestMethod -Uri $url -Method Put -ContentType application/json -Body $body

这是适合我的幻灯片校正,

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$token = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($personalAccessToken)"))
$headers.Add("Authorization", "Basic $token")
$headers.Add("Content-Type", "application/json")
$definitions = Invoke-RestMethod -Uri "https://devops.domain.com/Collection/Project/_apis/build/definitions" -Method GET -Headers $headers

ForEach ($definition in $definitions.value) {
    $definition.triggers = (@{ triggerType = 'continuousIntegration'; branchFilters = 'master', 'feature/*' })
    $definition.revision++

    $body = $definition | ConvertTo-Json
    Write-Host $body

    Invoke-RestMethod -Uri "https://devops.domain.com/Collection/Project/_apis/build/definitions/$($definition.id)?api-version=5.0" -Method PUT -ContentType application/json -Body $body -Headers $headers
}

似乎是从 list method cannot be used directly with the update method. This is quite clear in the list response type BuildDefinitionReference which doesn't include properties such as triggers. The definitions must be obtained from the get method using the definition IDs from the list method. This returns a BuildDefinition which does indeed have the triggers property. This can then be modified and passed to the update method 收到的定义。

这是工作代码:

$header = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($personalAccessToken)"))}
$definitions = Invoke-RestMethod -Uri "https://devops.domain.com/Collection/Project/_apis/build/definitions" -Method GET -Header $header
$branchNames = 'master', 'feature'

ForEach ($definition in $definitions.value) {
    $definitionToUpdate = Invoke-RestMethod -Uri "$($collection)$($project.name)/_apis/build/definitions/$($definition.id)" -Method GET -Header $header
    $trigger = $definitionToUpdate.triggers | Where {$_.triggerType -eq 'continuousIntegration'}

    if ($trigger) {
        $trigger.branchFilters = $branchNames | % {"+refs/heads/$_/*"}
        Invoke-RestMethod -Uri "https://devops.domain.com/Collection/Project/_apis/build/definitions/$($definition.id)?api-version=5.0" -Method PUT -ContentType application/json -Body ($definitionToUpdate | ConvertTo-Json -Depth 10) -Header $header
    }
}

代码在更新其分支过滤器之前检查 CI 触发器是否存在。