6
votes

I've been tasked with setting up a new Team Foundation/Build server at my company, with which we'll be starting a new project. Nobody here currently has experience with TFS, so I'm learning all of this on my own. Everything is working so far; The server's been set up, the Repository and Team Project has been created, the Build Server has been created, and I've created a simple hello world application to verify the source control and Continuous Integration builds (on the build server) run properly.

However, I'm having a problem setting up the automatic versioning. I've installed the TfsVersioning project, and it's working fine; I'm able to define a format for my assembly versions. I haven't yet decided what format I'll use; probably something like Major.Minor.Changeset.Revision (I'm aware of the potential problem regarding using the changeset number in the assembly version, so I may decide to switch to Major.Minor.Julian.Revision before we begin development).

The problem: I don't want assemblies to have new file versions if their source code has NOT changed since the last build. With a continuous Integration build this isn't a problem, as the build server will only grab the source files that have changed, causing an incremental build which produces only updated modules; the existing unchanged modules won't be built, so their version will remain unchanged. If I set up a nightly build, I'll want to clean the workspace and perform a Build-All. However, this means that ALL assemblies will have new version (assuming the Assembly File Version includes the build number).

A solution? This has prompted me to consider using the latest changeset number in the Assembly File Version. This way, if nothing has been committed between two successive Build-Alls, the versions won't be incremented. However, this would mean that a change and commit to a single file would force a version increment on ALL assemblies.

I'm looking for one of two things:

  • A way to only increment Assembly Version Numbers if their source/dependencies have changed since the last build. Successive Build-Alls should not cause changes in version numbers.

OR

  • A way for testers and non-developers to be able to tell version W.X.Y.Z and version W.X.Y.Z+1 of assembly 'Foo' are identical, even though they have differing file versions.

I've probably read about 20 articles on the subject, and nobody (except this guy) seem to address the issue. If what I'm asking for isn't common practice in the Team Foundation ALM, how do I address the second bullet point above?

Thanks for your time!

1
Why do you need people to be able to tell if two versions of a dll are identical? Usually testers/users just need to know what version of the Product they are using, and don't ever look at individual dll's.Dylan Smith
Out testers want to know exactly which modules have changed when we respond to a task or bug report. They claim that if all of the assemblies have different versions, then literally everything needs to be tested. Admitting I don't have a ton of experience in software testing, but perhaps this is an obvious and common repercussion? Should I tell our testers "of course you have to test everything"? (We plan to have proper unit-testing in this new project, smaller predictable functionality would not need to be tested for iterative builds.)Tsherr
In theory everything needs to be re-tested. Changing one DLL could potentially affect other (unchanged) DLL's which depend on it. In practice it is usually not reasonable to test everything on every change, and it is the QA Lead's job to determine which tests should be run when. But I typically recommend that you version the entire product, and not individual assemblies.Dylan Smith
Auto increment version numbers while source has been changed is not too difficult, you can use Major.Minor.ChangesetId.CreationDateOfTheChangeset pattern to determine the version of the project. Have a look at UpdateVersion.targets, it's a msbuild target file which will query history from TFS and update version numbers automatically on release build.bigsan
Thanks for the comments. bigsan, I think we've evaluated our procedures, and it seems like synchronized version numbers for all modules in the project are the way we want to go.Tsherr

1 Answers

2
votes

This is something I did in the past. The solution has two critical points:

  1. You must use an incremental build, i.e. Clean Workspace = None
  2. The change to AssemblyInfo.cs must be computed at each project

This latter is the most complex and I will just draft the solution here.

In the custom MSBuild properties use CustomAfterMicrosoftCommonTargets to inject an hook in normal Visual Studio compile

/property:CustomAfterMicrosoftCommonTargets=custom.proj

Also forward a value for the version

/property:BuildNumber=1.2.3.4

In custom.proj redefine the target BeforeCompile to something similar

<Target Name="BeforeCompile"
Inputs="$(MSBuildAllProjects);
        @(Compile);                               
        @(_CoreCompileResourceInputs);
        $(ApplicationIcon);
        $(AssemblyOriginatorKeyFile);
        @(ReferencePath);
        @(CompiledLicenseFile);
        @(EmbeddedDocumentation); 
        $(Win32Resource);
        $(Win32Manifest);
        @(CustomAdditionalCompileInputs)"
Outputs="@(DocFileItem);
         @(IntermediateAssembly);
         @(_DebugSymbolsIntermediatePath);                 
         $(NonExistentFile);
         @(CustomAdditionalCompileOutputs)" 
Condition="'$(BuildNumber)'!=''">

<Message Text="*TRACE* BuildNumber: $(BuildNumber)"/>

<MyTasksThatReplaceAssemblyVersion
    BuildNumber="$(BuildNumber)"
    File="$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs"/>
</Target>

You need to have a task for replacing the AssemblyFileVersion in the AssemblyInfo.cs source. MSBuild Extension Pack has an AssemblyInfo task for this purpose.

I posted the full details at my blog here, here and here.