Team City Meta Runner - Get Build Status
When building a deployment pipeline, the choice of tool is less important than the use of the tool: do you go for a tool that centrally controls the flow of a release, from build to running tests to actual deployment, or do you choose separate tools that are loosely hung together and execute a particular part of a release? From personal experience, I have preferred to use a tool to act as a control flow of the deployment pipeline, but leverage tools where there is clear sense to use them.
A case in point is using TeamCity to run the builds/package NuGet packages/run tests etc. TeamCity is great for these. But even though it can run a deployment no issues, some tools, such as Octopus, a great at managing this part of the pipeline, not least because it is great for environment management. Octopus also has a great and simple API, which the website itself uses to execute actions. It’s a great example of dog fooding/drinking your own champagne*. And so it’s easy to communicate betyween Octopus and TeamCity using this API.
But with regards to it’s API TeamCity is no slouch either. There is a huge amount of information available via the API. And from a usability point of view, one of the many things I like about the TeamCity API is that it can make use of the credentials of the build agent service account it is running under to access the API. So no need to pass username/passwords of some obscure account when invoking a web request.
So, we can use the API to help integrate applications with TeamCity, or to script interactions withiin TeamCity itself. And it is on the second point that today’s post pertains to. The execution of builds are very linear, and almost fatalistic: that is, one step follows another step, and though it is possible to control whether a step is executed dependent on the status of the build, it’s not possible to action a scenario if status of the build is a “success” or “failure” because there’s no way to determine the status of the build for sure. Until now: you can create a Meta Runner to set the value of a parameter to the value of the current status of the build, which can be extracted via the API. Using this value you cancontrol what action you want to take place next: raising a defect, sending email etc etc.
“But what is a meta runner?” I hear some of you ask. To quote the TeamCity documentation, “a meta-runner is a set of build steps from one build configuration that you can reuse in another; it is an xml definition containing build steps, requirements and parameters that you can utilize in xml definitions of other build configurations. TeamCity allows extracting meta-runners using the web UI. With a meta-runner, you can easily reuse existing runners, create new runners for typical tasks (e.g. publish to FTP, delete directory, etc.), you can simplify your build configuration and decrease a number of build steps.” So in our scenraio we are going to create new meta runner that will call the TeamCity API to get the current status of the build currently running and set this to a parameter that we create beforehand. And although meta runners are written in XML, you can add script code that will be executed when the runner is called.
But how can we get the status of the build? The TeamCity API has a default build locator that will return only the currently runing builds: “http://[teamcityserver]/httpAuth/app/rest/builds?locator=running:true”.
It will return, yes you guessed it, a list of builds that are currently running, including their build id, percentage complete, and the current status. And it’s this last one we care about.
Once we get the list of running builds, we can locate our build by using the %build.id% of the build that is running the meta runner against the list returned. Then it’s just a case of setting the value of the status to a PowerShell parameter, then setting that value to a TeamCity parameter, and this status can be passed between the build steps. Easy!
The PowerShell that the meta runner runs is below:
And below is the full meta runner. Be sure to alter the url to your TeamCity instance!
Now there’s one bit of “magic” that I’m not wild about which I need to explain here, but I don’t see an alternative. The last line run in the PowerShell pertains to TeamCity setting the value of a TeamCity from a PowerShell parameter. And so outside of this Meta Runner we need to create a TeamCity parameter called “RunningBuildStatus”. This parameter is at a global level, so when it is instantiated at the beginning of the build it is whatever you set the default value to; you cna leave it blank, or set it to “success” by default (as all builds start off with this status.) But once this meta runner is executed, the current status of the parameter becomes the current status of the build. And then in further builds you can have a piece of PowerShell that checks the value of “%RunningBuildStatus%”. This makes build steps far more deterministic and allows us to control the flow based on the known status of the build.
Now that I’ve explained how the Meta Runner works, let’s go through the steps of getting it up and running on a build, and then execute a piece of code dependent on the status of the build.
To get it on the build, you need to save a meta runner as an xml file to upload to TeamCity. Head to the “Administration” page of the project and choose “Meta Runners”. Then upload to TeamCity.
Right, its uploaded. Now we can make use of the runner in our builds.
- Create a new build step.
- From the drop down select the meta runner “Get Build Status”
- Name if whatever you want!
- The step is not part of your build.
- Add a parameter forthe build.
- Make sure it is named “RunningBuildStatus”
- The value can, and probably should remain empty.
- Now this tep is not necessary and even if you do add it it can be deleted later. But to test that this setup works Add a PowerShell step.
- Have it run smething simple where it inherits the value ofthe TeamCity parameter “RunningBuildStatus” and outputs it when building.
- If all has gone to plan then the status will output as part of the buikd.
*or idiom of your own choice.