Automating Deployment: Building/Deploying a Specific Mercurial Tag on CruiseControl.NET

Over the past few weeks, I've been claiming control of more of the build/deployment processes where I work. I was getting tired of seeing a red icon on CCTray because half of the company projects didn't build, and the few that had unit tests weren't even running them :-(

With all that addressed, I turned my attention to the process of deploying code to the staging servers. We wanted this to be as simple as possible, however it needs to be a conscious decision - we could not just have the public stage systems (used by clients, trainers, etc.) constantly building every time someone commits.

I like the way GitHub works but sadly we have no chatroom/chatbot to order to deploy for us! :-( We decided that a reasonably simple solution was to have a Mercurial tag called "Stage" to act as a flag for deploying. Once we're happy to push to stage, we can just pull the Stage tag up to the correct revision, and the build server can run with it.

To do this, we needed to add another project to CruiseControl.NET. One will build continuously (and update local test sites, for non-devs to test during development), and the other will deploy to the public staging environment. The problem came when I wanted to set up this new project to build from a tag. The CruiseControl.NET documentation (if you can find it - Google is polluted with tons of copies of old/stale documentation!) didn't seem to give any option for checking out a tag, only a branch! I tried putting the tag name in there in the hope it might still work, but sadly, no such luck!

I came across some info online that pointed me to "hg help urls" which shows you can use URL fragments to check out revisions, like this:

hg clone \\myserver\Development\MyRepo#Stage

This worked great on my machine, so I configured CCNet to use this as the repository. Unfortunately the build failed immediately, with this error:

abort: repository \\myserver\Development\MyRepo#Stage not found!

At first I thought maybe CCNet was doing something fruity, but after trying the same command on the build server from a command window, I discovered that this functionality has become broken in a recent version of Mercurial!

I've filed a bug on the Mercurial site and for now, rolled the server down to 1.7.3 (the version I had on my desktop, which I knew worked). This meant uninstalling TortoiseHG, but that's not the end of the world, right? ;-)

Now the CCNet config looks something like this:

<sourcecontrol type="hg">	
	<repo>\\myserver\Development\MyRepo#Stage</repo>
	<autoGetSource>true</autoGetSource>
	<workingDirectory>$(WorkingPath)\$(ProjectName)</workingDirectory>
	<purgeModifications>true</purgeModifications>
	<revertModifications>true</revertModifications>
</sourcecontrol>

With this now working, things were starting to come together. To make things even easier, I added an alias in my Mercurial.ini file:

[alias]
stage=tag -f Stage

There's still a little way to go to fully automate the process of extracting the build on the server, but what used to take 30+ minutes is now as simple as:

  1. Type "hg stage"
  2. Go and make a cup of tea for the team
  3. Build server will:
    • Check out the Stage tag
    • Overwrite the AssemblyVersion attribute in a shared AssemblyInfo.cs file with the CruiseControl label
    • Build the project using MSBuild/NANT
    • Run all tests
    • Zip up the resulting build and store it alongside previous versions
    • FTP the zip file up to the staging server ready for deployment
  4. Extract the zip file into the "Latest" folder (this is where most client IIS hosts point)
  5. Profit

Automating the last part is a little more tricky because we'll need something on the server to extract the zip (possibly a web service we can call, or a services that watches the folder for the releases), but if you consider that I deployed 6 times in the last 2 days and it's taken only 4-5 hours to automate this much, it's clear the savings will mount up!

 

If you likey, then why not Subscribe to my RSS feed or follow @DanTup on Twitter? :)