Friday, July 11, 2014

Automated Builds and Incrementing Version Numbers

Incrementing the version number when you do a build in Visual Studio seems an obvious requirement.

I found this great post on using a T4 template.  I followed the instructions carefully by creating a common DLL library project, removing the Class1.cs and adding a AssemblyVersion.tt file using the code that was provided. 

As the author points out you just need to save the T4 template file and it will create a .cs file with the assembly information in it with the appropriate build number.  In my case it created a AssemblyVersion.cs file.

As advised, I removed the  AssemblyVersion and AssemblyFileVersion attributes from AssemblyInfo.cs files of all the projects  that I wanted to apply this version number to. 

I then added the AssemblyVersion.cs file to the projects as a link but I moved the file under the Properties folder so it appears directly under AssemblyInfo.cs. If you've not added a link before, select Add existing.. and select the file and you will see the Add button in the dialog has a little down arrow which will reveal the "Add as a link" option. 

Sure enough when I built the solution, my DLLs had the correct version  number. 

But I realised I had to manually save the T4 file each time to refresh the version.cs file.  Now I want to have automated builds so I was looking for a way to process the T4 template before each build.

I finally found the answer from this blog entry. There is a TextTransform.exe file that will take the T4 template and produce the cs file. 

TextTransform.exe is located here
\Program Files\Common Files\Microsoft Shared\TextTemplating\11.0

or

\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\11.0

In the Pre-Build event of the version project I added this
"C:\Program Files (x86)\Common Files\Microsoft Shared\TextTemplating\11.0\TextTransform.exe" ($ProjectDir)AssemblyVersion.tt -out ($ProjectDir)AssemblyVersion.cs

When I build the solution the version number is incremented.  Brilliant.

You can of course use lots of different variations for incrementing the build  or revision number. But remember the 4 parts are

major.minor.build.revision

I changed the original template to modify the AssemblyFileVersion only and not the AssemblyVersion.  I am still able to distinguish between the DLLs from different builds but the all important AssemblyVersion I control.  The first deployment will be version 1.0.0.0, I can then branch the code and change the T4 template to the next release 1.1.0.0.

To increment from the previous revision number using a T4 template there is a good blog post here. If you want to change both build and revision number use methods which use the declaration starting with <#+
using System.Reflection;
[assembly: AssemblyCompany("C Hoare & Co")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.<#= BuildNumber() #>.<#= RevisionNumber() #>")]
<#+
private int BuildNumber()
{
    int buildNumber = (int)(DateTime.UtcNow - new DateTime(2014,7,1)).TotalDays;
 return buildNumber;
 }
#>
<#+
private int RevisionNumber()
{
    int revisionNumber = 0 ; 
   // other code to increment revision number
    return revisionNumber;
}
#>

A couple of further points. 
1. Make sure there is no white space after the final #> or you will get an error.
2. If using TFS then add to the pre-build event, get latest version of AssemblyVersion,cs, check out before the TextTransform. In the Post Build event check the cs file back in.
3. To pause incrementing the build number, just unload the project from the solution.
4. SharePoint 2010 only recognises the major and minor number of the AssemblyVersion.  That's why controlling the AssemblyVersion is important, but you can increment the AssemblyFileVersion instead.

UPDATE
When I started using this method for automatic builds, I realised that using Pre and Post Build events to process the T4 template produced some errors.  I moved the commands into a PowerShell script and I execute this as a scheduled task an hour before my scheduled builds run.  I still have the version project but it becomes simple  container for the T4 template and the CS file, I don't need to add it to any solutions. I still like this approach. I have one place where I control Assembly and Assembly File Versions.

No comments: