如何使用 Azure DevOps REST Api 编写构建计划脚本?

How to script build schedule using Azure DevOps REST Api?

这个问题是我另一个问题的延续 -

我不知道如何编写构建计划的脚本。 API 我应该使用什么?

编辑 1

我想强调 - 我不想每 5 分钟自己对构建进行一次排队。我想编写构建时间表。因此,我在定义更新 REST Api - https://docs.microsoft.com/en-us/rest/api/azure/devops/build/definitions/update?view=azure-devops-rest-5.1 中,但仍然不明白如何更新构建定义的时间表。打开 Fiddler 并对 API 进行逆向工程的建议让我觉得这没有记录在案。这是否意味着我基于流量分析实现的任何内容都可能在下一个版本中被破坏?

编辑 2

使用建议的解决方案有效。这是我的代码,基于提供的答案。我必须改变两件事:

  1. 正文应该是标量对象,而不是数组。所以,我将 $BuildDefinition 而不是 @($BuildDefinition) 转换为 json.
  2. 我使用 Windows 身份验证,因为我们有一个内部部署的 Azure DevOps 服务器。

$BuildDefinition | Add-Member triggers $triggers -Force

$json = ConvertTo-Json $BuildDefinition -Depth 99 

$Url = $BuildDefinition.url -replace '(.+)\?.+',"`?api-version=5.0"
Invoke-RestMethod -Uri $url -Method Put -Body $json -ContentType "application/json" -UseDefaultCredentials

但是,构建定义对象必须通过GET API, not the LIST API获取。后者 returns 构建定义的简化版本,不能用于更新它。

编辑 3

使用完整符号指定分支非常重要,即 refs/heads/master 而不是 master。使用后者似乎有效——创建了计划,分支过滤器看起来正确,但它不起作用。问题是 GUI 没有给出任何错误指示。

如果您的意思是使用 REST API 设置构建计划,那么您可以使用 Definitions - Update

您也可以在浏览器中按 F12 来跟踪 API 时从 UI 设置时间表。

回到您的要求:

How to schedule an on-premise Azure DevOps build to run every 5 minutes?

正如您提到的,目前本地 Azure DevOps Server 不支持 YAML 中的计划。用于定义基于时间的构建触发器的 UI 不够灵活。 因此,我们无法像内置功能那样实现这一点。

但是我们可以调用 queue build REST API 使构建每 5 分钟排队一次,我们有两种方法可以做到这一点:

  1. 写个脚本调用REST构建队列API,然后运行就可以了 定期在客户端机器上,我们可以用 Windows Task 设置它 调度程序。参考以下博客来做到这一点:

  2. 在脚本中硬编码,打开一个控制台到 运行 任何脚本 可以访问 Azure DevOps Server 的客户端(在 PowerShell 下 脚本对我有用):

示例:

Param(
       [string]$collectionurl = "https://server/DefaultCollection",
       [string]$projectName = "ProjectName",
       [string]$BuildDefinitionId = "11",
       [string]$user = "username",
       [string]$token = "password/PAT"
    )

    # Base64-encodes the Personal Access Token (PAT) appropriately
    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))

    function CreateJsonBody
    {

        $value = @"
      {
      "definition": {
        "id": $BuildDefinitionId
      }

    }
    "@

     return $value
    }

    $json = CreateJsonBody

    $uri = "$($collectionurl)/$($projectName)/_apis/build/builds?api-version=5.1"


    $EndTime = Get-Date
    while($true) {
        $EndTime = $EndTime.AddMinutes(5)

        ###Queue build###
        $result = Invoke-RestMethod -Uri $uri -Method Post -Body $json -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}


        Start-Sleep -Seconds $( [int]( New-TimeSpan -End $EndTime ).TotalSeconds )
    }

更新1:

要在启用计划触发器的情况下更新构建定义,我们需要在请求正文中附加触发器属性。

GET build definition 通过调用 REST API,使用响应作为请求主体。

在响应请求正文中附加触发器属性:

"triggers": [
    {
        "schedules": [
            {
                "branchFilters": [
                    "+refs/heads/master"
                ],
                "timeZoneId": "UTC",
                "startHours": 5,
                "startMinutes": 20,
                "daysToBuild": 31,
                "scheduleJobId": "5e8e3663-2d1c-482e-bb4d-91f804755010",
                "scheduleOnlyWithChanges": true
            }
        ],
        "triggerType": "schedule"
    }
]

更新2:

好吧,您可以使用下面的 PowerShell 脚本来 enable/update 通过更新构建定义来触发构建计划:

Param(
   [string]$collectionurl = "https://server/DefaultCollection",
   [string]$project = "projectname",
   [string]$definitionid = "183",
   [string]$user = "username",
   [string]$token = "password/PAT"
)

# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))

$ErrorActionPreference = 'SilentlyContinue' 

#Get resonse of the build definition
$defurl = "$collectionurl/$project/_apis/build/definitions/$($definitionid)?api-version=5.1"            
$definition = Invoke-RestMethod -Uri $defurl -Method Get -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}

#Set trigger array


 $triggers =  ' 
        [{
            "schedules": [
                {
                    "branchFilters": [
                        "+refs/heads/master"
                    ],
                    "timeZoneId": "UTC",
                    "startHours": 9,
                    "startMinutes": 40,
                    "daysToBuild": 31,
                    "scheduleOnlyWithChanges": true
                }
            ],
            "triggerType": "schedule"
        }]'


 cls
#Add a trigger block to the response body

$definition | Add-Member -NotePropertyName "triggers" -NotePropertyValue (Convertfrom-Json $triggers) -Force

Remove-TypeData System.Array  # Remove the redundant ETS-supplied .Count and values property

#Convert the response body to Json
$json = @($definition) | ConvertTo-Json -Depth 99 

#Update build definition
$updatedef = Invoke-RestMethod  -Uri $defurl  -Method Put -Body $json -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}

Write-Host ($updatedef.triggers | ConvertTo-Json -Depth 99)