How to override the TFS Build number and force TFS to include files changed during the build

I had an interesting problem today.  My current client uses a custom file to store build numbers in their application and that file gets used to show the number in a couple of places in the app.  TFS defaults its build numbers to _YYYYMMDD.# format, which was confusing when we were dropping the files to the build directory.  They used to have a manual process where they would physically change the revision number on this custom file before each build.  I automated that process with MSBuild/VSS a few months ago, so I had to tweak the custom task to work with VSS.  TeamBuild has a target called BuildNumberOverrideTarget, which does exactly what its name says, override the build number before all the build *stuff* happens.  So within that target, I can call my custom task that changes the file with the new version number (basically, looks at the old version number and increases it by 1).  Once you have your version number, you set the BuildNumber property, which is then used by TFS in the build process.

TeamBuild figures out the last checkin before the build started and uses that to label and get latest.  Since I am making a change to a source controlled file from within the build, my changes were not making it to the build.  For that, I had to set the changeset number that TFS should use as a reference.  I made a change to my custom task so that it returns the changeset ID for my checkin.  You then need to set the GetVersion property, which is also defined by Microsoft.TeamFoundation.Build.targets, which is the default target used by TFS.   So my target looks like this:

<Target Name = BuildNumberOverrideTarget >

    <AutoUpdateVersion Server=$(TeamFoundationServerUrl)>
      <Output TaskParameter=Major PropertyName=MajorNumber />
      <Output TaskParameter=Minor PropertyName=MinorNumber />
      <Output TaskParameter=Build PropertyName=BuildNumber />
      <Output TaskParameter=Revision PropertyName=RevisionNumber />
      <Output TaskParameter=ChangeSetId PropertyName=GetVersion />
    AutoUpdateVersion>

    <PropertyGroup>
      <BuildNumber>$(MajorNumber).$(MinorNumber).$(BuildNumber).$(RevisionNumber)BuildNumber>
    PropertyGroup>
  Target>

In order to interact with TFS source control from code, this is what you need to do:

  • Add references to Microsoft.TeamFoundation.Client, Microsoft.TeamFoundation.VersionControl.Client, Microsoft.TeamFoundation.VersionControl.Common
  • Connect to TFS
  • Create a Workspace on the build machine
  • Set a working folder for your workspace
  • Get latest to the working folder
  • call PendEdit(), which basically checks out the file. 
  • Call your function to update the file
  • Call CheckIn(), which returns the changeset ID

Here’s a code-snippet (simplified for demo purposes):

  1. //The _Server variable is provided from the build definition
  2. TeamFoundationServer tfs = TeamFoundationServerFactory.GetServer(_Server);
  3. VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
  4.  
  5. Workspace workspace = vcs.CreateWorkspace(“VersionWorkspace”, vcs.AuthenticatedUser);
  6. string localPath = Path.Combine(Path.GetTempPath(), “TFSVersionUpdate”);
  7. string localFilePath = Path.Combine(localPath, “VersionFile.cs”);
  8.                                                 
  9. WorkingFolder folder = new WorkingFolder(_FilePath, localPath);
  10. workspace.CreateMapping(folder);
  11. workspace.Get();
  12.  
  13. workspace.PendEdit(localFilePath, RecursionType.None);
  14.  
  15. //Call update function
  16.  
  17. _ChangeSetId = “C” + (workspace.CheckIn(workspace.GetPendingChanges(), “Automated build number update”)).ToString();
  18. workspace.Delete();
  19.  
  20. return true;
Scroll to Top