Several hours today were spent advancing my automated build process for Chef. I’ve had CruiseControl.NET building the software for months now but I’ve had a gaping hole in the processes that has been staring at me since I started it.
What is this hole you ask? Version numbering.
Why is versioning so hard in this day and age? Seriously. With .NET there are all these really nice and easy attributes that all you have to do is type in the version string you want your assembly/binaries to have. That works really well, until you want those numbers to be dynamic – then it requires modifying a sourcecode file with a new hard coded string. But what about 1.0.*? you ask, referring to the ability to have the compiler generate parts of it for you. Well, what real good is it to have version numbers that you don’t control? If they get generated by the compiler it just makes everything difficult – like translating between a version label from CruiseControl to the state of source control at the time of the build. Maybe I’m missing something here, but I don’t think I am.
Another versioning issue is setup projects. The setup projects created in Visual Studio have a version number, product code, and upgrade code. Counter to intuition, the upgrade code is the same across versions for a given product and it’s the product code that changes between versions. Sooo, if you bump the version number you also need to create a new Product Code guid. Again, there’s no way (that I know of) to do this via command-line. Microsoft thinks you should open the setup project and bump the version number manually. They even go as far as prompting you to create the new Product Code guid when you do this. Microsoft, the creator of the great tool that is Visual Studio, make it very hard to do the Right Thing and have automated builds. Tisk, tisk.
And finally, the version string has implications on product keys – both generation and verification. For instance, if Suzie buys Chef 1.2, I need to have a way to have that license key work for 1.2.5, 1.4, and 1.9; but not 2.1. And I need to be able to forget about the details rather than think about it every single time I create a release. (Chef Beta 2 is days away, by the way).
My solution to these problems required a little planning, a little coding, and a lot of time waiting for test builds to be created. My process is as follows.
- I go to the CruiseControl.NET Dashboard website and click Force to initiate the build.
- The last successful build label is incremented (from 0.9.2.2 to 0.9.2.3, for instance).
- The latest sourcecode is retrieved from the Perforce depot
- The code I wrote tonight gets executed on the sourcecode tree, passing in the newly incremented build number
- A new product code guid is generated
- Every AssemblyInfo.cs file is edited and all AssemblyVersion attributes are changed to use the new version number
- The specified .vdproj files (Visual Studio setup projects) are edited to modify the ProductVersion with a trimmed version of the current build version/label. The new ProductCode is also inserted
- Visual Studio is called upon to perform the compile.
- CruiseControl puts the generated installation packages out on the network
- A sourcecontrol Label is created in the Perforce depot, denoting the state of the sourcecode at the time of the build.
And that’s it. With a single click I have installation packages created with no further involvement. The files included in the package all have a version number that I can trace back to a CruiseControl label (to view build logs and in the future unit test results) and then back to a Perforce label with the same name to view the sourcecode files at were a part of the build. I’ll then also be able to compare those file versions with the recorded version numbers of bug fixes in FogBugz – something that will surely save time once Chef is in the wild.
Microsoft, please please please make this better in the future.