Cleaning up from Cancelled VSTS Builds

One of the questions that I get occasionally from teams using VSTS Build is what to do when a build is cancelled where that cancellation might leave state on the build machine in a bad state.

Cancellation can occur for a couple of different reasons but one of the most common reasons is that the build was triggered by a pull request being submitted and then an update to that pull request occurs triggering the cancellation of the first build (and queuing another one).

Up until now my advice has been to include a script in your build definition that detects these conditions and cleans them up at the commencement of the build process - however, this week I learnt about a neat trick that you can employ in the task.json file when defining custom tasks.

All you need to do is add a prejobexecution and postjobexecution to the task definition, and the agent will do the rest - here is a snippet to show how they are defined.

{
  ...
  "prejobexecution": {
    "Node": {
      "target": "pre.js",
      "argumentFormat": "
    }
  },
  "execution": {
    "Node": {
      "target": "exec.js",
      "argumentFormat": "
    }
  },
  "postjobexecution": {
    "Node": {
      "target": "post.js",
      "argumentFormat": ""
    }
  },
  ...
}

Basically the way it works is that when the VSTS agent downloads the build or release definition it will run all the defined prejobexecution scripts in the order that they appear in the build definition. When the build completes (pass, fail or cancel) the agent will run them in the reverse order.

Task authors can use this behavior to do clean-up operations when things don't go as planned in a build. The shipping VSTS tasks already make use of this feature in a few areas, for example the Install Apple Provisioning Profile task implements both a pre and post execution steps (but no execution step!).

Looking at the implementation of the prejobexecution step on the Install Apple Provisioning Profile task also shows another interesting trick - the tl.setTaskVariable(....) call.

You can use tl.setTaskVariable(...) to pass state from the pre step to the subsequent execution and postjobexecution phases. The tl variable is from the vsts-task-lib NPM module which provides an API to integrating your Node.js scripts into VSTS Build (there is also a PowerShell module).

Whilst I don't always recommend creating a custom VSTS task to meet your automation goals (simple scripts are often more than sufficient) this pre/post execution capability increases the benefits of building a custom task when recovery cancelled builds are required.