14

I have got a Team Foundation Server Build running cleanly. It produces several assemblies and I would like the assemblies versions to have the last number to be the changset number. That is, if I commit with a changeset11667 for example the assembly version number should be "x.y.z.11667". I've checked the availible macros, but none is the changeset number.

I would still like to be able to build the solution file on my dev machine as normal, just using the checked in version number.

How would I go about getting this in place?

vidstige
  • 12,492
  • 9
  • 66
  • 110

5 Answers5

7

Realize that this will stop working once you exceed 65,535 changesets. Perhaps you want to update some other field. BTW, yes, build engineering is engineering. Pointing at a solution and telling it to build is only the beginning of the journey.

Christopher Painter
  • 54,556
  • 6
  • 63
  • 100
  • 1
    yeah, thanks for the hint. At our current rate of check ins that will happen in roughly 32 years so I doubt we'll hit that cap. Out of curiosity, what is the cap? Is it the assembly version that is only 16 bits or is it the number of changesets limited in source control? – vidstige Apr 18 '12 at 13:50
  • also, an important enginerring principle is keep it simple. I want to be able build my solution by just checking it out and running without any scripts - The build server should mimic this as closely as possible to avoid problems it builds in the build server but not on my dev machine. Except a few extras of course that are only done on the build machine, just like the assembly version number. – vidstige Apr 18 '12 at 13:56
  • FILEVERSION - Binary version number for the file. The version consists of two 32-bit integers, defined by four 16-bit integers. For example, "FILEVERSION 3,10,0,61" is translated into two doublewords: 0x0003000a and 0x0000003d, in that order. Therefore, if version is defined by the DWORD values dw1 and dw2, they need to appear in the FILEVERSION statement as follows: HIWORD(dw1), LOWORD(dw1), HIWORD(dw2), LOWORD(dw2). – Christopher Painter Apr 18 '12 at 15:20
  • 3
    I'm sure people said that Y2K wouldn't be a problem in the 60's and 70's also. – Christopher Painter Apr 18 '12 at 15:20
  • 1
    Old developers made good money because of Y2K, so let us too develop something constained in time )) – Ivan Aug 06 '13 at 12:48
  • @ChristopherPainter +1 That's good to know, thanks! I also thought this wouldn't affect me -- until it dawned on me that we're nearly half-way there and our teams have only been using TFS for one year. And we're growing.. – Brian Lacy Feb 21 '14 at 22:37
  • My project collection at work is on 61694. My CodePlex project is in the 80k right now. – Christopher Painter Feb 22 '14 at 00:24
4

I am working on a tool to automate the build process it is still on development and it's open source here is the link (I am planning a release in about one week):

https://github.com/jupaol/NCastor

Now I would recommend you to check the Semantic versioning:

http://semver.org/

To get the latest changeset from TFS, you have several options:

I built a custom routine to do this

https://github.com/jupaol/NCastor/blob/develop/Solutions/NCastor.AutoBuilder/NCastor.AutoBuilder.Runner/Targets/Build/Versioning/VersionControlServers/TFS/GetTFSRevisionVersion.target

I had to build that routine because the Community tasks and the MSBuild Extenssions tasks were not working on a 64bits machine, if you are using a 32bits machine to build then you can use the following tasks:

Using http://msbuildextensionpack.codeplex.com/

<UsingTask AssemblyFile="$(ExtensionTasksPath)MSBuild.ExtensionPack.dll" TaskName="MSBuild.ExtensionPack.VisualStudio.TfsVersion"/>

Using http://msbuildtasks.tigris.org/

<UsingTask AssemblyFile="$(MSBuildCommunityTasksLib)" TaskName="MSBuild.Community.Tasks.Tfs.TfsVersion" />

Example to set the different versions:

<UsingTask AssemblyFile="$(MSBuildCommunityTasksLib)" TaskName="MSBuild.Community.Tasks.AssemblyInfo" />

<MSBuild.Community.tasks.AssemblyInfo OutputFile="$(AssemblyVersionFilePath)"
          CodeLanguage="C#"
          AssemblyFileVersion="$(FileVersion)"
          AssemblyInformationalVersion="$(InformationalVersion)"
          AssemblyVersion="$(SemanticVersion)" />

Once you have created the file simply add that file as a link to each project and voila! all your projects are sharing the common assembly info.

Jupaol
  • 21,107
  • 8
  • 68
  • 100
  • Does your tool handle Semantic versioning somehow? Do you have a way of asking the user that checks-in/builds/merges the source for a new version number? – Danny Varod Aug 08 '13 at 12:44
  • It uses the semantic versioning format. Before releasing, the version has to be updated following the semantic versioning rules – Jupaol Aug 13 '13 at 20:52
3

Have a look at the Community TFS Build Extension project on CodePlex. It contains an AssemblyInfo activity and the TfsVersion activity that are capable of changing the assembly info during the build process using a custom format.

To have it build on your dev machine you have to implement those build extensions on your own using batch files and the TFS command line utilities.

PVitt
  • 11,500
  • 5
  • 51
  • 85
  • alright, cool. So I would have to do some kind of special build. Today I only point out the solution file and it just works – vidstige Apr 18 '12 at 09:25
  • You can get the changeset number using the answer to this post: http://stackoverflow.com/questions/11748338/tf-exe-on-tfspreview/12923581 – Derek Evermore Oct 16 '12 at 21:31
3

In the end a colleague of mine wrote the following MSBuild task that solved the problem.

public class GetNextBuildNumber : Task
{
    [Required]
    public string TfsCommand { get; set; }

    [Required]
    public string TfsArgument { get; set; }

    [Output]
    public int BuildNumber { get; set; }

    public override bool Execute()
    {
        BuildNumber = GetLatestVersionNumber();
        return true;
    }

    private int GetLatestVersionNumber()
    {
        var process = new RunProcess();
        var result = process.ExecuteCommand(TfsCommand, TfsArgument);

        return ParseResult(result);
    }

    private int ParseResult(string result)
    {
        const string changeset = "Changeset:";
        const string user = "User:";

        if (string.IsNullOrEmpty(result) || !result.Contains(changeset))
        {
            // Invalid result
            Log.LogWarning("Could not get latest build number. Reason: " + result);
            return 0;
        }

        var indexOfChangeset = result.IndexOf(changeset, StringComparison.InvariantCulture) + changeset.Length;
        var indexOfUser = result.IndexOf(user, StringComparison.InvariantCulture);
        var revision = result.Substring(indexOfChangeset, indexOfUser - indexOfChangeset).Trim();

        return Convert.ToInt32(revision);
    }

}
vidstige
  • 12,492
  • 9
  • 66
  • 110
0

For what purpose are you wanted to do that ? If you want to have a relation between a DLL and the source code to pull from TFS the best way is to index the symbols using TFS Source Control in the PDB generation. This way when you debug any version of your software Visual Studio will get the right version of the source from TFS when needed.

Nock
  • 6,561
  • 1
  • 28
  • 27
  • I've got crash reporting using bugsense. I only get a stacktrace and a version number. To make sense of the stacktrace I need to know how the source looked at the time of the build. – vidstige Apr 18 '12 at 19:43
  • You can't ship the PDBs with your application? Looks like it's not for production purpose (I assume you'd know the version shipped). – Nock Apr 18 '12 at 19:55
  • Ship PDBs? Does not sounds like a good idea. It will be deployed using click once. Yes it is for "production", but its not yet released. And yes, I would like to know the version shipped. We "ship" daily for test and later we'll probably to a few ships before settling at a stable version. – vidstige Apr 18 '12 at 20:03
  • Then I strongly advice you to ship the PDB using an alternate click once definition. PDB are used to make the relationship between code in a DLL/EXE and the source code. You can active the "index build in PDB" feature in Team Build in just one click (with TFS 2010), go for it. – Nock Apr 18 '12 at 20:22
  • Okay, but cant I just store the PDBs at my place instead? Whats the point of shipping the pdb? – vidstige Apr 18 '12 at 20:24
  • Because the PDB will change each time you build your app, then "your place" would certainly contain only the latest PDB, then it won't work. The best practice is to put the PDB in the same directory of its dll/exe. There's no harm/fault to do that internally in your company. IIRC click once pack the files and PDB do pack well, so don't bother, use the PBD: your debugging experience will be greatly improved. – Nock Apr 18 '12 at 20:31
  • when I write 'ship' I mean: Give to a customer. Therefore I do not want to ship the PDBs. We store all build artifacts in house. Binaries, pdbs, everything. Only a clickonce is shipped without pdbs etc. Hope this clearified things. – vidstige Apr 03 '13 at 11:49