Monday, 29 July 2013

TFS versioning

I have found following guid, but not wrote it. All credit goes to author on link below.



Incrementing the build number, and versioning the assemblies, is a simple process with the help of the Microsoft SDC Tasks ( There are two aspects to versioning a Build in TFS, first is versioning the TFS Build number and the second is versioning the assemblies in the build. Both of these are reasonable simple to do.


The first thing to do is place the SDC tasks assembly on your team build server. I found the easiest way of doing this, and to allow different builds to use different versions, was to add the assembly to the build folder in TFS along with the tasks definition file.

The top of the Tasks file will need to be customised to match your environment by supplying, or ensuring, that the taskspath property is set correctly, for me changing the property group to the following worked.

    <BuildPath Condition="'$(BuildPath)'==''">$(MSBuildProjectDirectory)\</BuildPath>
    <TasksPath Condition="Exists('$(BuildPath)\Microsoft.Sdc.Tasks.dll')">$(BuildPath)\</TasksPath>

You will also need to include the tasks file in your project file by adding the following line to your .proj file.

<Import Project="$(MSBuildProjectDirectory)\Microsoft.Sdc.Common.tasks" />

Now you can customise the version numbers.

1. TFS Build Number.

TFS provides a ''BuildNumberOverrideTarget'' which should be used to modify the build number. This is the appropriate place to load and configure the build number for the entire solution by outputing a ''BuildNumber'' property.

In my solution I load the version number using the SDC's VersionNumber.Update command. To keep track of the Version number and to ensure they are always unique I keep the version.xml used by the task in Source control and check it in and out of TFS using the TF command line. This can be seen in the scripts below. (the structure of the Version.XML file can be found on the SDC codeplex site, see link below.)

TFS will then use this build number for the build rather than its built in one. 

2. Versioning the assemblies.

Once you have a build number you usually want to adjust the AssemblyInfo.cs files to match the build number. 

I do this by creating my own target ''VersionAssemblies'' which I attach as a dependency to the Team build ''AfterGet'' target. The process is simple... first collect all the AssemblyInfo.cs files into an item group and then use the SDC File.Replace task to do a regular expression search and replace all the assembly version lines to the new build number.


Information on the tasks used to accomplish this script can be found on the

Full credit also to the numerous blog articles I can't remember reading that pointed me the right direction for desiging this receipe.


    <TfCommand>&quot;C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\tf.exe&quot;</TfCommand>
<Target Name="BuildNumberOverrideTarget" DependsOnTargets="CoreInitializeWorkspace">
    <!-- First get and check out the version files.-->
    <Exec Command="$(TfCommand) get /force /noprompt &quot;$(MSBuildProjectDirectory)\version.xml&quot;"
          ContinueOnError="true" />
    <Exec Command="$(TfCommand) checkout &quot;$(MSBuildProjectDirectory)\version.xml&quot;"

    <!-- Now update the version number -->
    <VersionNumber.Update VersionNumberConfigFileLocation="$(MSBuildProjectDirectory)\version.xml"
      <Output TaskParameter="VersionNumber" PropertyName="BuildNumber" />

    <!-- Now check the version file back in. -->
    <Exec Command="$(TfCommand) checkin /override:&quot;Automated&quot; /comment:&quot;Update Version number $(BuildNumber)&quot; /noprompt &quot;$(MSBuildProjectDirectory)\version.xml&quot;"


<!-- This target is called after Team build gets all the source files from TFS. -->
<Target Name="AfterGet" DependsOnTargets="VersionAssemblies" />

<Target Name="VersionAssemblies">
     <!-- Get the Assembly Info files.-->
     <CreateItem Include="$(SolutionRoot)\Source\**\AssemblyInfo.cs;">
          <Output TaskParameter="Include" ItemName="AssemblyInfos"/>

     <!-- Update the version numbers -->
     <File.Replace Path="%(AssemblyInfos.FullPath)" NewValue="AssemblyVersion(&quot;$(BuildNumber)&quot;)" regularExpression="AssemblyVersion\(\&quot;(\d+.\d+.\d+.\d+)\&quot;\)" ignoreCase="true" />



  1. By making the BuildNumberOverrideTarget depend on CoreInitializeWorkspace the build is forced to initilize the workspace before the buildnumber target. This makes it possible (as long as the full path is used) for the version.xml to be checked in and out of TFS the first time the build is run. (Which was a problem with the previous version.)
  2. The ''AssemblyVersion'' line in the AssemblyInfo.cs files must exist for it to be found and replaced. This shouldn't usually be a problem as it usually does exists anyway.

No comments:

Post a Comment