In Azure DevOps, in Continuous Integration, in Pipeline build setup, using YAML build setup, is it possible, when I complete do many pull request during the same minute, and system start queuing the builds, because my system do build each time I accept a pull request on my master branch, is it possible to specify the system to cancel the current build to directly start the new one?
There is no built-in option can be used to easily set the pipeline to automatically cancel the running builds and only run the latest triggered build.
As a workaround, you can try to configure like as below:
Create a variable group (RunningBuilds), and add two variables (defId_{definitionId} and varGroupId).
{definitionId}
with the actual definitionId
of your YAML pipeline (e.g., defId_75
). The value is the buildId
of the current running build. The initial value is 'null
'.variableGroupId
of current variable group. You can find the value from the URL of this group displayed on the address bar of browser.On the Security of the variable group, ensure the following identities have the Administrator
role assigned. Replace {Project-Name}
and {Organization-Name}
with the actual names of your Azure DevOps organization and project.
{Project-Name} Build Service ({Organization-Name})
Project Collection Build Service ({Organization-Name})
Go to "Project Settings" > "Service connections" to create a new Generic service connection.
https://dev.azure.com/{Organization-Name}/
. Replace {Organization-Name}
with the actual name of your Azure DevOps organization.Go to your YAML build pipeline, on the Security of the pipeline, ensure the identities mentioned above have the following permissions are set to 'Allow
'.
View builds
Update build information
Queue builds
Manage build queue
Edit queue build configuration
In the pipeline, add a new stage to run before all other stages like as below.
trigger:
branches:
include:
- master
variables:
- group: RunningBuilds
stages:
- stage: cancelBuild
jobs:
- job: cancelPreviousBuild
variables:
previousBuildId: $[variables.defId_${{ variables['System.DefinitionId'] }}]
pool: server
steps:
- task: InvokeRESTAPI@1
displayName: 'Cancel previous build'
condition: ne(variables.previousBuildId, 'null')
inputs:
connectionType: 'connectedServiceName'
serviceConnection: 'InvokeAPI'
method: 'PATCH'
headers: |
{
"Content-Type":"application/json",
"Authorization": "Bearer $(System.AccessToken)"
}
body: |
{
"status":"cancelling"
}
urlSuffix: '$(System.TeamProject)/_apis/build/builds/$(previousBuildId)?api-version=7.1'
waitForCompletion: 'false'
- task: InvokeRESTAPI@1
displayName: 'Update Variable Group'
inputs:
connectionType: 'connectedServiceName'
serviceConnection: 'InvokeAPI'
method: 'PUT'
headers: |
{
"Content-Type":"application/json",
"Authorization": "Bearer $(System.AccessToken)"
}
body: |
{
"name": "RunningBuilds",
"variables": {
"defId_${{ variables['System.DefinitionId'] }}": {
"value": "$(Build.BuildId)"
},
"varGroupId": {
"value": "$(varGroupId)"
}
},
"variableGroupProjectReferences": [
{
"projectReference": {
"id": "$(System.TeamProjectId)",
"name": "$(System.TeamProject)"
},
"name": "RunningBuilds"
}
]
}
urlSuffix: '_apis/distributedtask/variablegroups/$(varGroupId)?api-version=7.1'
waitForCompletion: 'false'
- stage: build
dependsOn: cancelBuild
. . .
With above configurations:
buildId
of the new build as the value of the variable defId_{definitionId} in the variable group, so that the next build can know it.