Saturday, July 11, 2009

Injecting a version number into WiX via TeamBuild

I have found several ways of injecting a version number into Wix via TeamBuild, but most of them require way too much work. After a few days of experimenting I ended up with this solution. My TFSBuild.proj file contains the Major and Minor versions and a target "GenerateBuildNumber" to generate build and revision numbers. I use these to create a 'Versionnumber' property and add that to the <custompropertiesforbuild> property.
<propertygroup>
  <assemblymajorversion>2</assemblymajorversion>
  <assemblyminorversion>7</assemblyminorversion>
  <custompropertiesforbuild>
    SignAssembly=true;DelaySign=false;AssemblyOriginatorKeyFile=$(PrivateKeyLocation)
  </custompropertiesforbuild>
</propertygroup>

<target name="BuildNumberOverrideTarget" dependsontargets="GenerateBuildNumber">
  <createproperty value="$(AssemblyMajorVersion).$(AssemblyMinorVersion).$(GeneratedBuildNumber).$(GeneratedRevisionNumber)">
    <output taskparameter="Value" propertyname="Versionnumber" />
  </createproperty>

  <!-- Add the dynamically generated Versionnumber to the custom build properties for use in the WIX project -->
  <createproperty value="$(CustomPropertiesForBuild);Versionnumber=$(Versionnumber)">
    <output taskparameter="Value" propertyname="CustomPropertiesForBuild" />
  </createproperty>
</target>
For setting the version number in a WiX project, you need to get the value in the Product.wxs file. My predecessor had defined PRODUCTVERSION to contain a placeholder value "_versionnumber_". Note: The official way would have been to use the <defineconstants> in the WiX project file but in my case, other builds were already depending on the placeholder so I didn't want to change this.
<?define PRODUCTVERSION="_versionnumber_"?>
In my WiX project file I have overriden the "BeforeBuild" target to replace the "_versionnumber_" placeholder with the actual value of $(Versionnumber). I'm using the 'File.Replace' task from the SDC Tasks library.
<Target name="BeforeBuild">
     <microsoft.sdc.tasks.file.replace
       Path="Product.wxs"
       OldValue="%22_versionnumber_%22"
       NewValue="%22$(Versionnumber)%22"
       Force="true"
       IgnoreCase="true">
   </Target>
As a final step, I have overriden the "AfterBuild" target of the WiX project to rename the output msi in order to contain the versionnumber in the filename as well.
<Target name="AfterBuild">  
 <Createproperty value="$(TargetDir)%(CultureGroup.OutputFolder)">  
   <Output taskparameter="Value" propertyname="TargetDir">  
 </CreateProperty>  
 
 <Copy sourcefiles="$(TargetDir)$(TargetName)$(TargetExt)"  
       destinationfiles="$(TargetDir)$(TargetName).$(Versionnumber)$(TargetExt)">  
   
 <Delete files="$(TargetDir)$(TargetName)$(TargetExt)">  
</Target>