Semantic versioning for dotnet application

Semantic versioning for dotnet application

Versioning application allows us to know which features are currently available in the environment where we deployed but when our application is composed by multiple webservers, it becomes tedious to maintain the versioning. On top of that with the dotnet core movement, management of versioning has changed. Today I will show a way to automate the versioning using Gitversion and how it can be used for dotnet core and dotnet framework. This post will be composed by 3 parts:

  1. Version assemblies
  2. Semantic versioning
  3. Gitversion

1. Versioning assemblies

In dotnet, assemblies are versioned via the AssemblyInfo.cs file. This file contains the metadata used by the compiler to populate the information about the assembly like the title, the author, the copyrights and the version.
It is handle via attributes. Here is an example of an assembly info file:

using System.Reflection;

[assembly: AssemblyTitle("HelloWorld")]
[assembly: AssemblyProduct("HelloWorld")]
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+24.Branch.master.Sha.6e4b39ab28bb63227d9c418a9460fe344c0bacb2")]

This assembly info will yield the following assembly:

img

In .NET Framework, the assembly info is added in the project template and can be found under the Properties folder of the project. We can directly edit this data and see the version of the assembly change when it is built.

In .NET Core, there is no assembly info generated by the template. It is actually auto generated at each build and can be found in /obj.

Having it auto generated simplifies the process as it is now possible to control all values for all projects in the solution by adding a Directory.build.props file at the root of the solution. This will set all properties for the whole directory hence can be used to set a single version for all assemblies.

It is also possible to disable the auto generation of the assembly info if we wish to continue to maintain physical assembly info files like with .NET Framework. This can be done by adding the following line in the csproj:

<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

Then we can add the AssemblyInfo.cs under properties.

2. Semantic versioning

Semantic versioning is used to maintain a version easily understood by maintainers and consumers.
It is composed by 3 numbers X.Y.Z each having a particular meaning. X stands for a MAJOR release, Y stands for a MINOR release, and Z stands for a PATCH release.

There are many scenarios where the different type matters but the most common are the following:

  • Major is used when breaking changes occur. In particular break of interfaces/protocol. This will prevent package managers to update the version of the assembly without having an explicit confirmation from the consumer.
  • Minor is used when new features are delivered or when important internal changes occur. It is recommended to update and is safe.
  • Patch is used when fixes are made to patch the system and it is safe to update.

This convention allows consumer to know what has been changed and whether it is safe or not to update the library by only looking at the version.

3. Gitversion

At every release, the developer releasing would need to deduce whether the next version is major, minor or patch.

To deduce that, we need to look at all the commit messages or code and make the decision about the version.

GitVersion is a tool created to apply semantic versioning to an application.

It can be downloaded on Github https://github.com/GitTools/GitVersion/releases.
After downloaded unzip the binaries, place it in a folder and register the folder in PATH in order to make available gitversion from cmd.

Next navigate to your repository and run gitversion.

> gitversion
{
  "Major":2,
  "Minor":0,
  "Patch":0,
  "SemVer":"2.0.0",
  "FullSemVer":"2.0.0+24",
  ...
}

As we can see here our version is 2.0.0. If we make a commit, our version will then be 2.0.1. We can see +1 beside the version, this is to indicate that there is 1 commit ahead of the previous released version.

> gitversion
{
  "Major":2,
  "Minor":0,
  "Patch":1,
  "SemVer":"2.0.1",
  "FullSemVer":"2.0.1+1",
  ...
}

Once we are ready to release, we then tag with the release number the commit which will be released. After tagging, the +n will dissapear and the tag version will be used.

> git tag 2.0.1
> gitversion
{
  "Major":2,
  "Minor":0,
  "Patch":1,
  "SemVer":"2.0.1",
  "FullSemVer":"2.0.1",
  ...
}

Now for gitversion to be able to detect whether it needs to bump the major, minor or patch digit, we need to provide some sort of indication. This indication comes from the commit messages in the form of regex strings.

The regex pattern is +semver: major|minor|patch. Patch does not need to be specified as it is the default bump for master. For the major and minor, the developer committing needs to add the pattern in the commit message so that when her branch merges back to master, gitversion will know how to version it.

For example here the current version is 2.0.1. If a developer makes a breaking change, we would commit with +semver: major. Next version will then be 3.0.0.

> git commit -m "some message +semver: major" --allow-empty
[master 655cbd2] some message +semver: major

> gitversion
{
  "Major":3,
  "Minor":0,
  "Patch":0,
  "SemVer":"3.0.0",
  "FullSemVer":"3.0.0+3",
  ...
}

We can see now gitversion knows that the next version is 3.0.0. Similarly, we can use +semver: minor to specify a minor change.

Lastly in order to automatically update the AssemblyInfo.cs, we can use the command from gitversion:

> gitversion /updateassemblyinfo

And that completes this post on how to version applications in dotnet!

Conclusion

Today we saw how we could version .NET Framework applications and dotnet core applications. We also had a brief explanation of what is Semantic versioning and why it is important. Lastly we looked at GitVersion, an open source software calculating the sementic version of the current branch removing the burdden to have to check manually and decide the version numbers. Hope you like this post! See you next time!

Comments

Popular posts from this blog

A complete SignalR with ASP Net Core example with WSS, Authentication, Nginx

Microsoft Orleans logs warnings and errors

One way to structure Web App built in F# and WebSharper