Pages

Showing posts with label Build. Show all posts
Showing posts with label Build. Show all posts

Sunday, 16 October 2011

TeamCity, msbuild and Version Numbers

How to automatically set all your solution’s projects to the same version number with msbuild and TeamCity?

We have a number of solutions mixing native and managed projects.

The mechanism we use to ensure all DLLs and EXEs have the same version number relies on modifying 2 files:

  • A VersionInfo.h file for native projects
  • A VersionInfo.cs file for managed projects

The .h file contains something like this:

#define PROJECT_VERSION 3,9,0,1234
#define PROJECT_VERSION_STR “3.9.0.1234”

All native projects in the solution have a resource file (.rc) that includes this unique VersionInfo.h.  This is how the exe/dll obtain their version info.

On the .NET side, the VersionInfo.cs file contains:

[assembly: Assemblyversion(“3.9.0.1234”)]
[assembly: AssemblyFileversion(“3.9.0.1234”)]

All managed projects in the solution compile this VersionInfo.cs file (using a soft link, no duplication necessary).

So all we have to do in order to ensure that the 30+ binaries have exactly the same version number is to get our build script to modify the .h and the .cs just before building the solution.

Sounds easy!

Then there is the question of where to store the “3.9.0.1234” version. It should be in one single place of course. An obvious choice seems to be the TeamCity build number.

From Major.Minor.Build.Revision, we can set Major.Minor.Build by hand in TeamCity and have the Revision set automatically to the current SVN revision number, which is a handy way to relate builds to SVN revisions.

In the TeamCity project settings, the build number format field looks like this:

3.9.0.%build.vcs.number.MyProject_SVN_Root%

ScreenHunter_01 Oct. 15 18.37

Then within our msbuild XML file we refer to the build number set in TeamCity like this:

$(BUILD_NUMBER)

The following msbuild lines update the version number stored in the VersionInfo.cs.

    <FileUpdateFiles Files="VersionInfo.cs"
      Regex="(\d+)\.(\d+)\.(\d+)\.(\d+)"
      ReplacementText="$(BUILD_NUMBER)"/>

This regex does wonders to replace “1.2.3.4” with “3.9.0.1234”. But now, more tricky: when doing the string replace in VersionInfo.h (it’s always the native projects that cause trouble Winking smile), how do you replace

#define PROJECT_VERSION 1,2,3,4

with

#define PROJECT_VERSION 3,9,0,1234

given the string in $(BUILD_NUMBER) “3.9.0.1234”.

Can’t do anything a bit subtle with msbuild without having to download and install third-party tasks… So I’m currently looking into the TextString task from the MsBuild Extension Pack to tokenise the version string and then concatenate it back to the appropriate format. It’s all a bit complicated, there must be an easier way to do this…

Update (16/10/2011):

It’s actually not that bad, here is the code that formats $(BUILD_NUMBER) and updates the .h /.cs VersionInfo files.

    <TextString TaskAction="Replace"
                OldString="$(BUILD_NUMBER)"
                OldValue="."
                NewValue=",">
      <Output PropertyName="FormattedBuildNumber"
              TaskParameter="NewString"/>
    </TextString>
    <Message Text="Replacing version in VersionInfo.h with $(FormattedBuildNumber) and $(BUILD_NUMBER)">
    </Message>
    <FileUpdateFiles Files="VersionInfo.h"
      Regex="(\d+)\.(\d+)\.(\d+)\.(\d+)"
      ReplacementText="$(BUILD_NUMBER)"/>
    <FileUpdateFiles Files="VersionInfo.h"
      Regex="(\d+)\,(\d+)\,(\d+)\,(\d+)"
      ReplacementText="$(FormattedBuildNumber)"/>
    <Message Text="Replacing version in VersionInfo.cs with $(BUILD_NUMBER)">
    </Message>
    <FileUpdateFiles Files="VersionInfo.cs"
      Regex="(\d+)\.(\d+)\.(\d+)\.(\d+)"
      ReplacementText="$(BUILD_NUMBER)"/>

Sunday, 1 November 2009

Trying out TeamCity and CruiseControl

A few teams use Cruise Control at work. It seems to be a fairly standard choice when it comes to continuous integration. Roy Osherove recommends TeamCity over CruiseControl because he doesn't like getting his hands dirty with XML configuration (can't blame him).

I tried both to get a feel of what you can do with them. I ran TeamCity of my main machine and CruiseControl on a VM to avoid clashes.

I managed to get a build running in TeamCity without too much difficulty. I installed the tray notifier.

CruiseControl is a bit more tricky. After I edited the config files I kept getting exceptions when trying to startup ccnet.exe. Had to go through several install iterations before getting something running.

Installing TeamCity:
  • Install Tortoise SVN
  • Install VisualSVN Server
  • Run the TeamCity installer
  • Start the build agent manually (rather than through a Windows service).
  • Install the TeamCity Windows tray notifier


Installing Cruise Control inside a virtual machine.
  • Windows Virtual PC RC, wich is a new version of Virtual PC for Windows 7.
  • Install Virtual Server 2008
  • Install SVN command line  
  • Edit the ccnet.config file
  • Get the Web Dashboard working:
    • Install IIS: under Windows Server 2008, it's not a Windows feature any more, it's a server role. You have to go to Server Manager > Roles > Add Roles and follow the wizard to add IIS.
    • Run the CruiseControl.Net installer
    • Create a new application in IIS for the ccnet webdashboard. In Server Manager, go Roles > Web Server (IIS) > Internet Information Services, open Sites > Default Web Site. Right-click Default Web Site and choose Add Application. Set Application Pool to Classic .NET AppPool.