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.
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.