How to automate ARM template versioning

The gentle art of making versions

Are you like me, always forgetting to update version numbers? If so, I got an interesting thing to show to you. Would it be nice that you could handle version bumping (almost) automatically in Azure DevOps. And would it be awesome that you could inject this version number to ARM templates. Well, let’s have a look how to do it with Azure DevOps, with the help of some nice components from Visual Studio Marketplace.


GitVersion is a handly tool to automate versioning. There’s Azure DevOps Build task for GitVersion in Visual Studio Marketplace that you can simply drop to your build pipeline and let it do it’s magic. GitVersion handles versioning with semantic versioning principles and uses GitHub Flow branching strategy as default.

Semantic version

SemVer is versioning method that has simple rules how version numbers are constructed. To put it simple, semantic version has three numbers: major, minor and patch, for example 1.0.0.

  • Major version is updated when there’s backwards incompatible changes.
  • Minor version is updated when backwards compatible functionality is added.
  • Patch version is updated when bug fixes are made.

GitHub Flow

GitHub Flow is very effective branching strategy for continuous delivery. Development with GitHub Flow goes as follows:

  • You create a branch from master
  • Do the needed development in branch
  • Create and send a pull request
  • Make possible changes in pull request
  • When happy, merge branch to master
  • Finally delete merged branch

Manifest Versioning Build Tasks

Manifest Versioning Build Tasks is a set of Azure DevOps build tasks that can be used to inject version numbers to source code. For example you can use Version JSON File task to update contentVersion in ARM templates. There’s also other tasks in package, but here I use only Version JSON File -task.

Let’s put this all together

Now that I’ve introduced all the prerequisities, it’s time to put this thing together.

I’ve prepared a resourcegroup to Azure containing a storage account with blob container. Let’s say that I want to create a Logic App with http trigger that creates blobs with the data from the trigger body.

DevOps project and Visual Studio solution

First let’s create a DevOps project for our Logic App development.

Now let’s skip few steps here and assume that we are familiar how to create a git repo to your DevOps project and clone and connect it to Visual studio.

Now we have the repo cloned and Visual Studio started. now we need our solution.

Lets choose Logic App Azure template.

And here we have the first version of our Logic App.

Now we can push the initial version of our code to Git remote master.

Next we jump over to DevOps and create a build pipeline for the first build.

Build pipeline

Here we have our build pipeline with four tasks: GitVersion, Version JSON File, Build solution and Publish Build Artifacts. Note that to be able to use GitVersion and Version JSON File, you must install them first to your DevOps.

In GitVersion task we don’t need to setup anything.

But let’s configure the Version JSON File.

  • Change the Version Number to $(GitVersion.SemVer), which is output variable from GitVersion task.
  • In Advanced tick Inject Version
  • Change Filename Pattern to .json
  • Change The version to update to contentVersion

Build Solution and Publish Build Artifacts tasks can be left in their default state.

And now to the exciting part: Save & Queue the build pipeline.

First build

Notice that build number has now the initial version (0.1.0+1) that GitVersion determined by the commits in our repo.

But what about ARM template contentVersion. Let’s have a look. Download LogicApp.json from build Artifacts drop folder and open it.

And there it is: our 0.1.0 version in ARM template instead of the default version value.

Now we’ve deployed and tested our solution and want to make it first 1.0.0 production release.

First production release

Now, how we manage to make our 0.1.0 version to 1.0.0? Well, we just tag the latest (in our case first and only) commit with the version.

Next we head back to build pipelines and start the build.

Once the build has ran we see that now we have version 1.0.0

And same version is in the ARM template in build artifacts.

Next release

Now let’s develop our Logic App further and take a look how our versioning works.

First let’s create a new branch

Then head to Logic App for some changes. Our major change is that, instead of constant name for the blob, we now want to include timestamp to our blobname, like this:

Save changes to solution and commit and push changes.

Now queue new build. But before starting, let’s change branch to dateblobs so we’ll get source from our newly created branch.

And now we have version 1.0.1-dateblobs.1+1 built. Notice how GitVersion added metadata to the end of the version number.

Now we can for example deploy our build to dev/test env and create a pull request to have our code approved. So let’s make a pull request. You can create a pull request from Visual Studio or in DevOps Repo. Actually Visual Studio opens up same browser view that creating Pull Request in DevOps would.

Let’s Approve and Complete the pull request.

We merge pull request and delete the dateblobs branch.

Next let’s see what happens to version when we build from master.

Let’s say we want this change to be a major change and so we tag it to release 1.1.0 in our repo.

And again, when we build we have release 1.1.0 as a version for our solution as a result.


Along this process I have deployed the logic app to resourcegroup with release pipeline. And here you see how version number is also visible in releases.

Finally we can have a look our deployed logic app in azure. There you’ll see the contentVersion also.


So handling ARM template versions couldn’t be more easier than this. Just remember to keep on track when tagging releases to repository, so you don’t accidentally skip versions. The methods I’ve shown here don’t limit to ARM templates. You can easily version for example WebJobs, Functions and so on. For projects that produce assemblies, you can include GitVersion as Nuget-package into your project.

If all this made sense to you and/or helped you in any way, or if you have ideas to make this better, give me a shout on Twitter or Linkedin. Also if you think I was totally wrong about something, I’d appreciate feedback.

Thanks for reading, and be seeing ya!

comments powered by Disqus