Continuous Integration, its sooooo last week. If you’re thinking about getting into CI, you’re behind the curve. Seriously. Fear not though, it’s a simple matter to not only continuously integrate, but to continuously deploy your application (which, by the way, is a form of continuous improvement (But I’ll stop spouting now. (Honest))).

What is Continuous Integration

Continuous integration is a well established software development technique used by teams all over the world. Martin Fowler describes it better than I can:

“Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.”

Great! Solves problems of team members not running tests and helps to (though does not ensure) promote regular and small checkins to source control. It means that when I get latest from TFS I’m much more likely to get code that works. But it doesn’t solve all your problems.

What Continuous Integration Doesn’t Do

In our SCRUM team we have developers working on local copies of the system who benefit hugely from CI. But we also have product owners who need the latest copy of the application – NOW.

Consider Joanne, a non-fictional analyst on our team. She’s logged 15 bugs in the last couple of days (we were having a sloppy week, what of it?) of which I’ve fixed 10 – resolving them on checkin. These are all sat happily in our latest CI build so get propagated to all the other developers PCs, but when Joanne goes to check them on the test server everything is still broken! So she comes over to me complaining that she can’t get on with her work until I put the latest build on the test server. I drop what I’m doing to deploy it and we both end up wasting time and effort, not to mention getting frustrated at each other.

Continuous Deployment

Enter continual deployment. In this fancy new version of CI, each integrated build is deployed somewhere. In the example above we will always deploy to the test server. This has the same benefits for all the non-dev team members as CI had for the devs:

  • The version of the system they see is the same as the developers see;
  • Fixes get to them for testing faster;
  • If the work item in TFS says it's fixed, it will be on the test server.

Now, that somewhere doesn’t have to be the test server. The holy grail of CD in fact is to be continually deploying to the live environment. Yeah, right, I can hear you saying. You remember the days before unit testing (you don’t? You lucky, lucky thing) and you can remember the frantic dash to fix issues deployed to live (or even the fixes done on live back in the days of classic asp) before anyone important notices. But these are not those days. These days we have automated unit tests, automated integration tests, automated UI tests! Most importantly we have well defined acceptance criteria for your product backlog items, allowing you to create those tests in confidence.

I’m sure that you looked at that and shook your head; it’s a rare team that pulls all those things together well enough that they can be confident enough to deploy to live on each checkin. It can be done though, flickr have been continually deploying to live for a long time now, and their site isn’t exactly a piece of crap. Generally though, it’s an ideal to work towards which can streamline and speed up your development process.

I’m Convinced Already, Just Show Me How To Do It!

OK, OK, here we go then. Let’s start by learning to crawl.

Setting Up Continuous Integration

I’m assuming a few prerequisites here:

  1. You are running on TFS 2010;
  2. You have permission to create build definitions;
  3. Your code is in source control!
  4. You have a series of unit tests in a test project.

First, we set up the build definition. In team explorer, open up your team project and its Builds node. Right click and select New Build Definition:

The dialog that pops up has 6 panes, the first of which asks for a name and description. Ignore the next pane and click into Workspace which, if your environment is anything like ours, will contain quite a few working folders. Generally you will only need one workspace here for the project you are building, so delete the rest:

Next up is the Build Defaults pane; in here select a build controller (don’t have one? Take a look here) and specify a network path to copy the output of the build to. Even if you don’t intend to save every build it’s a good idea to do this at first while you test the process.

Now move onto the Process pane, this is where you customise your build when you start doing funky stuff like deployment. For now though just change the Projects To Build item to point to the project file of your web project and add a configuration to build. Finally, change the Automated Tests item so that the wildcard search will pick up your test project:

The final pane contains settings for how many previous builds to keep. In general I turn this number right down, as you can always build a previous changeset anyway, but its personal preference.

Save your new build definition and it will appear in team explorer. Right click it and select Queue New Build. This will fire up the Build Explorer window and will display your build in it. After a while it should show up as finished. Click into it now.

The screen in front of you is truly a wonderful creation. At the top is information about how long the build took, followed by information on any warnings or errors found during the build (there were errors? Go fix your build now, we’ll wait!).  If you check the output folder you specified you should see your built project.

The last step is to have this happen on every checkin. Edit your build definition and on the Trigger tab select Continuous Integration. That’s it! Now do a checkin of your code against a work item and check the Build Explorer – you should see a new build kicking off. Once this is done have a look at the results. At the bottom you should see something like this:

Cool right? You’ve got a changeset associated with your build and an associated work item. You might also have some impacted tests.

Awesome, we’re continually integrating. Next up, let’s appease Joanne.

Setting Up Continuous Deployment

The technology we’ll be using for our deployment is MsDeploy. This is a service which will integrate with IIS 6 or 7 and allow you to automatically upload your application to a virtual directory (or even create one). The first step is to get it installed and started on your test server. Take a look at the installation walkthrough on the Microsoft IIS site for help with that.

All installed? Great, let’s get deploying! Right click on your web project in solution explorer and select ‘Publish’. You should see a screen similar to this (you may have to select ‘New…’ in the top combo):

You’ll need to use your own settings here obviously! The account you use will need to have permissions to edit the virtual directory (or local admin for the entire box if you’re on IIS6). Click ‘Publish’ and with a little luck you’ll get a Publish Succeeded’ message in the status bar.

Take a look at IIS now and you should see a virtual directory for TestSite. You can set up all the settings for this such as framework version, default pages etc and they will be remembered on subsequent publishes (it is actually possible to package these settings up on IIS7 but its beyond the scope of this post). Visit the site in the browser and ensure it works.

All that remains is to get this deploy happening as part of the CI build. For this we will need a few command arguments using the same values as in the dialog:

/p:DeployOnBuild=True
/p:DeployTarget=MsDeployPublish
/p:MSDeployPublishMethod=RemoteAgent
/p:CreatePackageOnPublish=True
/p:DeployIisAppPath="WebRoot/TestSite"
/p:MsDeployServiceUrl=MyTestServer
/p:username=zg\c6029126
/p:password=MyPassword

If you don’t want a user and password including in this string you can just give the account used by the TFS build server permissions and leave those items out of the command string.

Now edit the build definition for the build we created earlier. In the Process tab expand the Advanced section and drop your command string in the MsBuild Arguments field:

We’re done! Save the build definition and check in some code. When the build finishes check your test server – the new version should have been deployed.

What Next?

What we’ve achieved here is great but there is plenty more we can do to streamline our processes. The obvious miss here is the database side of the equation – you might well be developing the database in line with the application, but currently it will need to be deployed manually each time. I’ll be writing soon about how you can deploy databases in this way, as well as how to customise your build process to deploy multiple webs to different locations on every checkin. If you’d like to be notified when I add a new post, you could always subscribe to my feed.