azure-devopscontinuous-integrationazure-pipelines

In Azure DevOps, How to cancel the current build to directly start the new one?


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?


Solution

  • 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:

    1. Create a variable group (RunningBuilds), and add two variables (defId_{definitionId} and varGroupId).

      • defId_{definitionId}: Replace {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'.
      • varGroupId: The value of this variable is the variableGroupId of current variable group. You can find the value from the URL of this group displayed on the address bar of browser.

      enter image description here

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

      enter image description here

    3. Go to "Project Settings" > "Service connections" to create a new Generic service connection.

      • Server URL: https://dev.azure.com/{Organization-Name}/. Replace {Organization-Name} with the actual name of your Azure DevOps organization.
      • Service connection name: A custom name of the service connection.

      enter image description here

    4. 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

      enter image description here

    5. 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: