0

This question is continuation of my other question - How to schedule an on-premise Azure DevOps build to run every 5 minutes?

I cannot figure out how to script the schedule for a build. What API am I supposed to use?

EDIT 1

I want to emphasize - I do not want to queue the build myself every 5 minute. I want to script a schedule of the build. So, I am at the Definition Update REST Api - https://learn.microsoft.com/en-us/rest/api/azure/devops/build/definitions/update?view=azure-devops-rest-5.1 and still do not get it how to update the build definition's schedule. The advice to open Fiddler and reverse engineer the API makes me think this is not documented. Does it mean that whatever I implement based on the traffic analysis may be broken on the next release?

EDIT 2

Using the proposed solution works. Here is my code, based on the provided answer. I had to change 2 things:

  1. The body should be a scalar object, not an array. So, I convert $BuildDefinition rather than @($BuildDefinition) to json.
  2. I use Windows authentication, because we have an on-premise Azure DevOps server.

$BuildDefinition | Add-Member triggers $triggers -Force

$json = ConvertTo-Json $BuildDefinition -Depth 99 

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

However, the build definition object must be obtain through the GET API, not the LIST API. The latter returns a reduced version of the build definition, which cannot be used to update it.

EDIT 3

It is very important to specify the branch using the full notation, i.e. refs/heads/master instead of just master. Using the latter appears to work - the schedules are created, the branch filter looks correct, but it does not work. The problem is that the GUI does not give any indication something is wrong.

mark
  • 59,016
  • 79
  • 296
  • 580

1 Answers1

3

If you mean setting the build schedule using REST API, then you can use Definitions - Update

You can also press F12 in browser to track the API when set the schedule from the UI.

Back to your requirement:

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

Just as you mentioned, currently On-premise Azure DevOps Server does not support schedules in the YAML. And the UI for defining time-based build triggers isn't flexible enough. So, we cannot achieve that like the built-in feature.

However we can call the queue build REST API to queue the build every 5 minutes, we have two ways to do that:

  1. Write a script to call the queue build REST API, then run it periodically on a client machine, we can set it with Windows Task Scheduler. Reference below blogs to do that:

  2. Hard-coded in the script, open a console to run the script in any client which can access the Azure DevOps Server (below PowerShell script works for me):

Example:

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 )
    }

UPDATE1:

To update the build definition with the schedule trigger enabled, we need to append the trigger attributes in the request body.

GET build definition by calling the REST API, use the response as the request body.

Append the triggers attributes in the response request body:

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

UPDATE2:

Well, you can use below PowerShell script to enable/update the build schedule trigger by updating the build definition:

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)
Andy Li-MSFT
  • 28,712
  • 2
  • 33
  • 55
  • Please, see **EDIT 1** – mark Oct 25 '19 at 13:16
  • @mark To set the build schedule you need to append the schedule attributes in the request body, please see the updated answer. – Andy Li-MSFT Oct 27 '19 at 09:19
  • Where is the schedule trigger schema documented? – mark Oct 27 '19 at 16:27
  • @mark No specific sample such as other attributes, however it's indeed mentioned in the document. Please check [BuildTrigger](https://learn.microsoft.com/en-us/rest/api/azure/devops/build/definitions/update?view=azure-devops-rest-5.1#buildtrigger) and [DefinitionTriggerType](https://learn.microsoft.com/en-us/rest/api/azure/devops/build/definitions/update?view=azure-devops-rest-5.1#definitiontriggertype) for details. So, we can Get the response to check the schema from an existing build definition. – Andy Li-MSFT Oct 28 '19 at 02:33
  • @mark Well, I wrote a PowerShell script to enable or update the build schedule trigger, please see the updated answer. – Andy Li-MSFT Oct 28 '19 at 10:17
  • What is the semantics of the `daysToBuild` parameter? I guess it is a bit mask with bit 0 corresponding to Monday and bit 6 to Sunday. – mark Oct 30 '19 at 00:16
  • @mark Not exactly sure the semantics, however according to my test it has the following values for the days: `Mon:1 Tue:3 Wed:7 Thu:15 Fri:31 Sat:63 Sun:127` – Andy Li-MSFT Oct 30 '19 at 08:26