Application Versioning in Azure pipelines


Isn't it bad when users can get the current version number of a running application? It can’t, but in many cases, developers forget it to implement or just don't do it because they can.

Recently I finalized a project with a few console and UWP applications. But after a while, I noticed that I can't see the application versions of any application. That’s why I started to write down this post.

In the “good old times” developers did not have thought about deployment pipelines. They’ve set the version number in a file, that's it. It was the time as the code was locked for a developer, so nobody was able to change the number at the same time. Now it’s different. This time we have distributed teams, which developing at the same time on similar or even the same files. It makes the versioning way harder, but simpler too. We have to build pipelines. A pipeline is literary the last instance who can change automatically the code. An outcome of a pipeline is a package which should never have changed anymore. So why not set the version number exactly here?

Versioning in a .Net Console Apps

When I start a console app, usually it prints out the current version number at start time. This is what I want to reach too.

Because I have already created a pipeline YAML-File, I add one step before the VSBuild@1 task. You should have this task too. 😉 Add the new task before the build step.

- task: PowerShell@2
displayName: 'Set App Version'
inputs:
targetType: inline
script: |
[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
$path = "$(pathToProjectFile)"
$doc = [System.Xml.Linq.XDocument]::Load($path)
$doc
.Element("Project")
.Element("PropertyGroup")
.Element("Version")
.SetValue("$(major).$(minor).$(patch).$(build)");
$doc.Save($path)

This step adds a short script which is looking and opens the project file as XDocument. Because the structure of a .csproj file ist always the same, I browse up to the element Version. Typically a project file does not contain this element by default. So feel free to put it in the file by your self. Please put it in the PropertyGroup section. For me, I entered a dummy version number as content in the Version element, like 1.0.0.

The PowerShell script expects a few variables, which I’ve added at the top of my pipeline file.

variables:
pathToTheProjectFile: {add here your path}
major: 1
minor: 0
patch: $[counter(variables['major'], 0)]
build: $(Build.BuildId)

The values of major and minor are obvious, but patch and build are different. The counter function is part of the pipeline engine and increases the given value for every build by one. It starts with the major value with no additional seed (its zero). My second dynamic value is set up by a pipeline parameter, the buildId.

All of that creates a new value for every build, which ist great to print out the version number at application start. You will find the number in the Assembly.GetExecutingAssembly().GetName().Version property.

Oh btw, this version number will be only shown in environments which uses the build package. It’s because I don’t save the new value in the code repository. If you like to do so, feel free to push the new value from your pipeline into a special branch or something else. 😁

Versioning in an UWP App

Actually, it's the same solution as it is for a console app. But a small thing is different. The version number is not set up in the project file. It's in the manifest file

- task: PowerShell@2
displayName: 'version package manifest'
inputs:
targetType: inline
script: |
[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
$path = "$(PathToYourProject)/Package.appxmanifest"
$doc = [System.Xml.Linq.XDocument]::Load($path)
$xName = [System.Xml.Linq.XName]"{http://schemas.microsoft.com/appx/manifest/foundation/windows10}Identity"
$doc.Root.Element($xName).Attribute("Version").Value = "$(major).$(minor).$(patch).$(build)";
$doc.Save($path)

Here I load the Package.appmanifest file as XML too. To find the version part of the filem I need a special route. Actually also it’s possible to select the version part by browsing through the elements. If you like to go this way, you need from the Identity element the Version attribute. Finally I take the variables to set the value.

If you like to show the version number somwhere in your application, use the Package.Current.Id.Version property to read the value.

Done 👍

Hopefully I was able to describe it in a simple way. Feel free to play with the numbers but be carefull, you have to note the rules of semantic versioning