versioning with teamcity and nant

I'm using TeamCity to run my builds for a few projects and find it very easy, reliable and intuitive. It integrates with Subversion and NAnt with little effort but one of the missing tasks I had was to version my assemblies with the build number, so I took it upon myself this week to sort that out.

TeamCity provides a build number pattern when you configure a build so I simply set that to "{0}" so I can provide the current build number - this becomes a nant property called ${build.number}.

Next thing to look at was changing the AssemblyInfo.cs file within each .csproj so that it picked up the assembly info and file info strings from a controlled place. My initial idea was to have nant poke an xml file before it was then embedded as part of the compilation, but this naturally didn't work as it needs to be a compile time constant. So I went with this:

using MyProject.Core.Build;
[assembly: AssemblyVersion(Build.Version)]
[assembly: AssemblyFileVersion(Build.FileVersion)]

This uses a very simple static class I created for this purpose:

namespace MyProject.Core.Build
    public static class Build
        public const string Version = "0.1.0";
        public const string FileVersion = "0.1.0";

That was it for C# code, time to modify the nant build file so that it replaces the version number from the build before it compiles:

    <property name="version.file" value="${project::get-base-directory()}
/> <property name="build.number" value="0" overwrite="false"/> <target name="compile" depends="init" description="compiles the application"> <move file="${version.file}" tofile="${version.file}.bak"/> <copy file="${version.file}.bak" tofile="${version.file}"> <filterchain> <replacestring from=".0" to=".${build.number}" /> </filterchain> </copy> <delete file="${version.file}.bak"/> <loadtasks assembly="c:\dev\thirdparty\nantcontrib-0.85\bin\NAnt.Contrib.Tasks.dll" /> <msbuild project="../product/MyProject.sln"> <!-- this property enables MSBuild 3.5 --> <property name="teamcity_dotnet_use_msbuild_v35" value="true"/> <property name="OutputPath" value="${build.dir}"/> </msbuild> </target>

This first creates a backup of the C# file and then uses the copy command to copy it back over the original whilst it replaces the ".0" string with the TeamCity provided build number property. It then deletes the back up file it created.
There are other ways of using NAnt to replace tokens, but this works out of the box without adding additional tasks in.
At the start of the script if this build is not being run by TeamCity a default value of "0" is being provided.

And that is it! My assemblies are all built now using the build number - I get the current major and minor version from the constant string and the build number from the continuous integration process.