A CI/CD Versioning Strategy for .NET Projects in VSTS

Recently I was co-presenting on DevOps with Azure and VSTS at a customer event with Rik Hepworth, a friend of mine from Black Marble. He gave a great talk about Real World DevOps with VSTS covering practical tips for managing build & deployment in VSTS. During the talk he described a couple of Visual Studio MarketPlace Extensions that Black Marble had written to help implement a reasonably-sophisticated versioning strategy in VSTS. I was impressed with this approach and so I thought I’d have a go at implementing it on one of my own Azure application deployments.

What was this approach…You ask?

Well to put it simply it revolves around implementing an application versioning strategy as follows:

The Major and Minor version numbers are defined manually by the Dev Team (Me!). The BuildId is auto-generated by VSTS, as is the Revision (which increments for each build that occurs on the same day to ensure uniqueness).  The clever bit is that this this version number is generated by the build in VSTS and injected into the .NET AssemblyInfo files during the build, so that you don’t have to rely on remembering to set them manually, which can be problematic – particularly when working in a large team. In fact, Rik’s recommendation was to set the .NET AssemblyInfo.* version numbers back to so that if ever a build that doesn’t come from our CI/CD pipeline is deployed to production, we will be able to see this instantly from the version number.

Here’s how I set it up on one of my own projects…

Adding the Build Tasks Extension

From the Visual Studio Marketplace, I searched for and installed the Manifest Versioning Build Tasks extension from Richard Fennel of Black Marble. Whilst in the Marketplace, I also installed Richard’s Build Updating Tasks extension (We’ll discuss this one a little later in the article).

Updating the Build Definition

In the VSTS project, I edited my build definition and added a couple of build variables for the Major and Minor version numbers.

Then I changed the build number format to match the definition outlined earlier.

Next, I added Richard’s Version Assemblies build task to my build definition prior to the build task itself. I left the task parameters at the defaults.

By default, this task will go through all the AssemblyInfo.* files in my solution and update the version number to match the generated build version number.

The next part of the strategy is to update the release definition so that once I have successfully deployed a build to my production environment, I never build the same minor version of the app again. To achieve this we need to increment the minorVersion build variable. Luckily there is also a task that does exactly this.

Updating the Release Definition

I edited the Release Definition, and added the Update Build Variable task to my production deployment task list after the deploy task. Therefore, if the deploy task fails the remaining tasks don’t get executed so the build variable doesn’t get updated.

That’s it! Once I tested a build and release I could see the new version numbers appearing on the website.

Great approach. Thanks to Richard & Rik at Black Marble.

About John Duckmanton 15 Articles
At work, I am a Cloud Solution Architect in the UK. AT home I am a self-certified code geek, gather, biker, and avid Sheffield Steelers Ice Hockey Fan.

Be the first to comment

Leave a Reply

Your email address will not be published.