Friday, May 04, 2007

Updating an assembly version with the Continuous Integration build

If you use continuous integration builds, one of the steps you want to consider is to have resulting assembly DLL marked with incremental version number. This way QA people will be less confused about the version of site they're testing. Among the numerous advantages it gives you an additional selling point for an Agile development process. It doesn't matter do you tag your build in the source control or preserve it on the hard drive waiting to be burned on deployment CD (BTW: the former is more Sorbanes-Oxley compliant).

You can use the CC.NET <Labeller> task offers automatic increment. I am not sure but it may be reset if CC server is restarted; if not - then you don't really have much control over this number. Original NAnt would require crazy workarounds, but NAntContrib library contains very useful task.

The process is pretty standard in the main steps - Cruise Control project checks out the files, passes the control to the NAnt build script, which builds it, runs NUnit tests and tags it. It includes the following tasks:

<target name="increment-version">
<property name="version.file" value="${CCNetArtifactDirectory}/version.number" />
<echo message="1.0.0.0" file="${version.file}" if="${not file::exists(version.file)}" />
<version path="${number.file}" buildtype="Increment" />
</target>
<target name="update-assembly">
<asminfo output="${assemblyinfo.file}" language="CSharp" if="${file::exists(assemblyinfo.file)}">
<imports>...</imports>
<attributes>
...
<attribute type="AssemblyVersionAttribute" value="${buildnumber.version}" />
</attributes>
</asminfo>
</target>
You can notice that the first script counts on CCNetArtifactDirectory variable, which value is passed down from the Cruise Control script by default. The variable points to the <ProjectName>/Artifacts folder which is created automatically under the Cruise Control root directory the first time the project is built.

Here is the trick - we keep the version.number file here ( increment-version task creates it if can't find). The content of the file initially set to 1.0.0.0 (or another value if you wish) and task will increment it, following the incremental settings and result is stored in the ${buildnumber.version} variable. The advantage of this approach is that while build script is a part of the solution, the version.number file logically belongs to the CC.NET project level. At least it's kept away from developers who can change it :). Another approach is to store version.number in the source control (of course outside the the path, observed by CC.NET), but then additional will be required to check file out, change and check back in, while not adding too much protection.

It is worth mentioning that <update-assembly> task will regenerate AssemblyInfo.cs file from scratch and it's up to you to restore the required settings. If you prefer to avoid this, use <script> with C# function which will gently vivisect the AssemblyInfo.cs file and replace just a version.

No comments:


© 2008-2013 Michael Goldobin. All rights reserved