Search code examples
c#tfstfs-2015

How to figure out the changeset a TFS 2015 build was build from?


I am distributing only binaries which were built by one of my TFS build definitions and each build receives a unique version number (1.0.$yy$dayofyear.$rev). The name of the build name contains this version number. The version number is set by a PowerShell script as the assembly version and the file version of the binary. I have only a build result rentention (including the built binaries in my drop folder) of 60 days and now I am wondering: How would I possibly figure out for some version number which is one year old which changeset it was built from so that I can have a look at the source code or rebuild exactly the binary? Do I have to add the changeset info somehow during my build explicitly? Do I have to encode the changeset number in my version number which is set during the build? Both ideas don't seem very ingenious.


Solution

  • I finally came up with a PowerShell script that I hook into my build definition as an additional build step just after a step that is similar to the one proposed here which sets the version attribute in all AssemblyInfo.cs files:

    $systDefinitionId = $env:SYSTEM_DEFINITIONID
    $buildDefVersion = $env:BUILD_DEFINITIONVERSION
    $buildDefName = $env:BUILD_DEFINITIONNAME
    $buildSourceVersion = $env:BUILD_SOURCEVERSION
    $buildSourceBranch = $env:BUILD_SOURCEBRANCH
    
    $SrcPath = $env:BUILD_SOURCESDIRECTORY
    $AllVersionFiles = Get-ChildItem $SrcPath AssemblyInfo.cs -recurse
    $AllVersionFilesCount = ($AllVersionFiles | Measure-Object).Count
    
    Write-Verbose "Updating $AllVersionFilesCount AssemblyInfo.cs files in path ""$SrcPath"" with source information."  -Verbose
    
    Write-Verbose "ID of build definition:      $systDefinitionId" -Verbose
    Write-Verbose "Version of build definition: $buildDefVersion" -Verbose
    Write-Verbose "Name of build definition:    $buildDefName" -Verbose
    Write-Verbose "Changeset to build:          $buildSourceVersion" -Verbose
    Write-Verbose "Branch to build from:        $buildSourceBranch" -Verbose
    
    foreach ($file in $AllVersionFiles)
    {
    (Get-Content $file.FullName) |
        %{$_ -replace 'AssemblyProduct\(""\)', "AssemblyProduct(""$buildDefName / $buildSourceVersion"")" } |
        %{$_ -replace 'AssemblySourceBranch\(""\)', "AssemblySourceBranch(@""$buildSourceBranch"")" } |
        %{$_ -replace 'AssemblySourceChangeset\(0\)', "AssemblySourceChangeset($buildSourceVersion)" } |
        %{$_ -replace 'AssemblyBuild\(""\)', "AssemblyBuild(@""$buildDefName / ID: $systDefinitionId / Version: $buildDefVersion"")" } |
    Set-Content $file.FullName -Force
    }
    

    I am modifying the AssemblyProduct attribute by writing into it the build definition name and the changeset which was used to create the binaries. Later on this info is visible on the properties of the exe or dll in Windows Explorer on the details tab.

    Moreover I have defined the custom attributes AssemblySourceBranch, AssemblySourceChangeset and AssemblyBuild to carry more detailed info. They all have the same structure, so for brevity only the source code of AssemblySourceChangeset:

    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
    public class AssemblySourceChangesetAttribute : Attribute
    {
      public AssemblySourceChangesetAttribute(uint changeset)
      {
        Changeset = changeset;
      }
    
      public uint Changeset { get; }
    }
    

    Should the info in the "publicly" visible product field not be enough to be able to rebuild the binary, one can still result to reflecting upon the exe or dll and read those custom attributes which have info on the source branch, the id and the version of the build definiton stored.