One of the neat things about TeamCity is that it gives you a great deal of control over your process. TeamCity is great to use as a control flow for your pipeline, especially if you are using Octopus to deploy. But one of the pain points here is keeping the parity between build/deploy versions in Octopus the same as in TeamCity. It’s important because it prevents users from having to jump between the UI’s to keep track of what is deployed where, especially if you are automating the whole process.
There’s several ways to keep the build numbers aligned, the most obvious being snapshot dependencies. However, snapshot dependencies can open up a world of pain: if builds are altered then a snapshot may become invalid when it’s not intended, so a build may trigger other builds being launched unintentionally.
Fortunately, there is a method to share build numbers amongst other builds without setting up snapshot dependencies. By using a meta runner, you can use the TeamCity rest api to grab a build number of a given build.
“What is a meta runner?” I hear some of you say…. to quote the TeamCity wiki:
“A Meta-Runner allows you to extract build steps, requirements and parameters from a build configuration and create a build runner out of them. This build runner can then be used as any other build runner in a build step of any other build configuration or template.
Basically, 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.
All meta-runners are stored on a project level, so they are available within this project and its subprojects only, and are not visible outside. If a meta-runner is stored on the level, it is available globally (in all projects).”
Sounds pretty neat. The xml is below:
<?xml version="1.0" encoding="UTF-8"?> <meta-runner name="Get Build Number"> <description>Obtains build number from preceding step</description> <settings> <parameters> <param name="UpstreamBuildID" value="" spec="text description='Build Configuration ID of Upstream Build' validationMode='any' display='normal'" /> </parameters> <build-runners> <runner name="Obtain Build Number" type="jetbrains_powershell"> <parameters> <param name="jetbrains_powershell_bitness" value="x86" /> <param name="jetbrains_powershell_execution" value="PS1" /> <param name="jetbrains_powershell_script_code"><![CDATA[$username = "%system.teamcity.auth.userId%" $password = "%system.teamcity.auth.password%" | ConvertTo-SecureString -asPlainText -Force $cred = New-Object System.Management.Automation.PSCredential($username,$password) $buildconfigID = "%UpstreamBuildID%" $QueryBuildURI = "https://[teamcityuri]/httpAuth/app/rest/builds/buildType:$buildconfigID/resulting-properties/build.number" $buildnumber = Invoke-WebRequest ` -Uri $QueryBuildURI ` -Credential $cred ` -Method GET ` -ContentType "application/xml" ` -UseBasicParsing Write-Host "##teamcity[Upstream.Build.Number '$buildNumber']"]] Write-Host "##teamcity[buildNumber '$buildNumber']"]]></param> <param name="jetbrains_powershell_script_mode" value="CODE" /> <param name="teamcity.step.mode" value="default" /> </parameters> </runner> </build-runners> <requirements /> </settings> </meta-runner>
Be sure to update [teamcityuri] in the script with your TeamCity url. You may also need to alter “https” to “http”. But once you upload that to TeamCity, you can select that from the build runner drop down on the create build step page.