This is post #37 in the Building Neno series. Please click here for a description of the Building Neno project and instructions on how to access the source code for this post.
Last week I wrote a post on getting Hg revision information into assembly versions. It works okay, but it has a small drawback. Because I'm putting the version information into two files, CommonAssemblyInfo.cs
and Version.cs
, I have to manually maintain the major, minor and build numbers in two places. And because I'm using all three assembly versions, I have to maintain those numbers on multiple lines as well. This morning I'm going to remove all the needless duplication.
I want to consolidate the assembly version numbers into one place for easy maintenance. The best place to do that is probably in the build project itself. Here I'm going to set up properties for the major, minor and build numbers as well as create the three assembly versions as replacement values for template tokens.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<UsingTask TaskName="HgVersionFile" AssemblyFile="References/MSBuildVersioning/MSBuildVersioning.dll" />
<PropertyGroup>
<SolutionName>StackingCode.Moja</SolutionName>
<Major>1</Major>
<Minor>0</Minor>
<Build>1000</Build>
<BuildText>Alpha</BuildText>
</PropertyGroup>
<ItemGroup>
<Tokens Include="AssemblyVersion">
<ReplacementValue>$(Major).$(Minor).$(Build).0</ReplacementValue>
</Tokens>
<Tokens Include="AssemblyFileVersion">
<ReplacementValue>$(Major).$(Minor).$(Build).$REVNUM$</ReplacementValue>
</Tokens>
<Tokens Include="AssemblyInformationalVersion">
<ReplacementValue>$(Major).$(Minor) $(BuildText) ($REVID$${Dirty$DIRTY$})</ReplacementValue>
</Tokens>
<Tokens Include="Dirty0">
<ReplacementValue></ReplacementValue>
</Tokens>
<Tokens Include="Dirty1">
<ReplacementValue>+</ReplacementValue>
</Tokens>
</ItemGroup>
<!-- ... -->
</Project>
These are tokens that will be swapped in using the TemplateFile
task from the MSBuild Community Tasks Project, before the HgVersionFile
task from MSBuild Versioning gets a crack at doing its token replacement.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<!-- ... -->
<Target Name="Version">
<!-- Properties\CommonAssemblyInfo.cs -->
<TemplateFile Template="Properties\CommonAssemblyInfo.template.cs" OutputFileName="CommonAssemblyInfo.temp1.cs" Tokens="@(Tokens)" />
<HgVersionFile TemplateFile="Properties\CommonAssemblyInfo.temp1.cs" DestinationFile="Properties\CommonAssemblyInfo.temp2.cs" />
<TemplateFile Template="Properties\CommonAssemblyInfo.temp2.cs" OutputFileName="CommonAssemblyInfo.cs" Tokens="@(Tokens)" />
<Delete Files="Properties\CommonAssemblyInfo.temp1.cs;Properties\CommonAssemblyInfo.temp2.cs" />
<!-- Version.cs -->
<TemplateFile Template="Version.template.cs" OutputFileName="Version.temp1.cs" Tokens="@(Tokens)" />
<HgVersionFile TemplateFile="Version.temp1.cs" DestinationFile="Version.temp2.cs" />
<TemplateFile Template="Version.temp2.cs" OutputFileName="Version.cs" Tokens="@(Tokens)" />
<Delete Files="Version.temp1.cs;Version.temp2.cs" />
</Target>
<!-- ... -->
</Project>
The template file is run through a TemplateFile
task, then a HgVersionFile
task, then another TemplateFile
task.
The first TemplateFile
replaces ${}
tokens with strings.
${AssemblyInformationalVersion}
becomes
1.0 Alpha ($REVID$${Dirty$DIRTY$})
The HgVersionFile
task replaces $$
tokens with values from Hg.
1.0 Alpha ($REVID$${Dirty$DIRTY$})
becomes
1.0 Alpha (875673902fee${Dirty1})
The final TemplateFile
task replaces any remaining ${}
tokens.
1.0 Alpha (875673902fee${Dirty1})
becomes
1.0 Alpha (875673902fee+)
Temporary files are used instead of using the same file as input and output -- doing that causes problems in the HgVersionFile
task. The temporary files are cleaned up with a Delete
task at the end.
The CommonAssemblyInfo.template.cs
file now looks like this...
using System.Reflection;
[assembly: AssemblyCopyright("Copyright 2010 - 2011 Adam Boddington")]
[assembly: AssemblyVersion("${AssemblyVersion}")]
[assembly: AssemblyFileVersion("${AssemblyFileVersion}")]
[assembly: AssemblyInformationalVersion("${AssemblyInformationalVersion}")]
The Version.template.cs
file now looks like this...
using System;
namespace StackingCode.Moja
{
public static class Version
{
static Version()
{
DateTime buildDate = DateTime.Parse("$UTCDATETIME$");
buildDate = DateTime.SpecifyKind(buildDate, DateTimeKind.Utc);
HgBuildDate = new DateTimeOffset(buildDate);
}
public static readonly string AssemblyVersion = "${AssemblyVersion}";
public static readonly string AssemblyFileVersion = "${AssemblyFileVersion}";
public static readonly string AssemblyInformationalVersion = "${AssemblyInformationalVersion}";
public static readonly DateTimeOffset HgBuildDate;
public static readonly int HgRevisionNumber = $REVNUM$;
public static readonly string HgChangesetId = "$REVID$";
public static readonly bool HgIsBuildDirty = $DIRTY$ == 1;
public static readonly string HgBranch = "$BRANCH$";
public static readonly string HgTags = "$TAGS$";
}
}
Overall a much cleaner and easier to maintain solution, without any need for preprocessor directives either.
The StackingCode.Moja.csproj
and StackingCode.Neno.csproj
files still have the BeforeBuild
tasks to copy a default file over CommonAssemblyInfo.cs
and Version.cs
(see the earlier post). I want to keep those tasks for users that don't have Hg installed, and for the AppHarbor build process which doesn't currently support Mercurial.
Happy versioning.
There are 0 comments.
browse with Pivot
Codility Nitrogenium Challenge
OS X Lock
HACT '13
Codility Challenges
Priority Queue
Architecture (13)
ASP.NET (2)
ASP.NET MVC (13)
Brisbane Flood (1)
Building Neno (38)
C# (4)
Challenges (3)
Collections (1)
Communicator (1)
Concurrency Control (2)
Configuration (1)
CSS (5)
DataAnnotations (2)
Database (1)
DotNetOpenAuth (2)
Entity Framework (1)
FluentNHibernate (2)
Inversion of Control (5)
JavaScript (1)
jQuery (4)
Kata (2)
Linq (7)
Markdown (4)
Mercurial (5)
NHibernate (20)
Ninject (2)
OpenID (3)
OS X (1)
Pivot (6)
PowerShell (8)
Prettify (2)
RSS (1)
Spring (3)
SQL Server (5)
T-SQL (2)
Validation (2)
Vim (1)
Visual Studio (2)
Windows Forms (3)
Windows Service (1)
Comments
Leave a Comment
Please register or login to leave a comment.