Wednesday, 28 September 2011

Assembly versioning (for .NET)

Like most people, I version my assemblies during the continuous integration build. This is achieved by generating a class file (I call it “AssemblyInfoCommon.cs”) during the build. It looks like this:

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly: AssemblyCompany("Acme")]
[assembly: AssemblyConfiguration("Branch.Release.1.0.xxx.xxx Debug")]
[assembly: AssemblyCopyright("Copyright © Acme 2011")]
[assembly: AssemblyFileVersion("1.0.xxx.xxx")]
[assembly: AssemblyInformationalVersion("1.0.xxx.xxx")]
[assembly: AssemblyProduct("PetShop")]
[assembly: AssemblyTrademark("Acme")]
[assembly: AssemblyVersion("1.0.xxx.xxx")]


Where…




  • “1.0.xxx.xxx” is the version number (we’ll come to the “xxx” value later")


  • The “AssemblyConfiguration” attribute breaks down as follows:

    • “Branch” is constant.


    • “Release” will vary depending on what you call your branches


    • “Debug” is the Visual Studio Solution configuration so will typically be “Debug” as shown or “Release”.




  • The company name, copyright notice and year all all passed in from the build script as variables.


  • The product name is whatever the project is called.



This is all pretty straight forward so far. However, down the years I’ve had problems with a strategy for the version number.



In the .NET world, the version number breaks down as follows:




[major].[minor].[revision].[build]




See MSDN.



Originally, the my version numbers broke down as follows:




1.0.yMMdd.x




Where “major” and “minor” are configured manually (these never automatically increment).



The “revision” number breaks down as follows:




  • “y” is the last digit of the current year. For 2011, this is “1”.


  • “MM” is obviously the month.


  • “yy” like wise for the day.



The “build” number represents the number of builds today, so the first build of the day takes “1”, the second “2” etc.



The would give you the following build numbers (I’m choosing old dates for a reason…):




  • 1.0.10926.1 – the first build on 26th September 2001


  • 1.0.11231.3 – the third build on 31st December 2001


  • 1.0.20101.4 – the fourth build on 1st January 2002



This worked pretty well for a number of years. Unfortunately, there is a constraint on the components of the version number that did not become apparent until 1st January 2006.



The first build number for 1st January 2007 was (in theory) “x.y.70101.0”. Unfortunately each component of the version number is an “Int32”. The largest value for an Int32 is “65534”, “70101” is bigger than this. Queue me getting build failure notification e-mails while on a beach in Thailand on New Year’s day, which was nice.



Since then, I’ve wrestled with a couple of different strategies but none ever really worked. The one I got most mileage out of was the same as before for Major, Minor and Build but had a different strategy for the Revision. I used the day of the year in combination with the year. So the Revision for…




  • 31st January 2011 would be “1031” (the 31st day of the year)


  • 2nd February 2011 would be “1032” (the 32nd day of the year)


  • 31st December 2011 would be “1365” (the 365th day of the year)


  • 1st January 2012 would be “2001” (the 1st day of the year)



This is problematic for two reasons:




  • You have to do maths to work out when a version was built.


  • Years ending in 0 (2010, 2020) cause problems because of leading zeros get dropped by the compiler. So 1.0.0001.0 (1st Jan 2010) would become 1.0.1.0 which is confusing.



Recently I’ve found a new strategy which works pretty well. The problem with the first strategy is fitting revision numbers for “high” years into an Int32, the problem with the second one is leading zeros. This third strategy overcomes this and breaks down as follows:




1.0.yyMM.ddxx




Where “major” and “minor” are as before.



The “revision” number breaks down as follows:




  • “yy” is the current year. For 2011, this is “11”.


  • “MM” is again the month.



The “build” number is as follows:




  • “dd” is the day.


  • “xx” is the build number of the day.



Examples:




  • 1.0.1109.2601 = 26/09/2011, 1st build of the day


  • 1.0.9912.3199 = 31/12/2099, 99th build of the day


  • 1.0.1201.0101 = 01/01/2012, 1st build of the day


  • 1.0.1112.3199 = 31/12/2011, 99th build of the day



There’s one caveat – best to not have more than 99 builds in one day but that is a highly unlikely scenario.


About Me