Tuesday, 6 October 2009

Get Your Build Under Control

If you’ve followed this blog in the past you’ll realise that I’m a real advocate of and in particular using during the build and environment creation process. Come to think of it, if I could write a Nant script to wash my car for me, I would have done it by now!

If you don’t use a CI system, I can’t recommend setting one up enough. I currently use which sits on a virtualized Windows 2008 server (my build server) but this post isn’t about evangelising CI, its about a change I’ve made to how I use it, which saves me time and will hope fully be of some use to you.

The image below outlines the folder structure I use on my build server:

branch

Notice the build-nnnnn folders which are separate build instances.

A new build instance begins automatically after I check some content back into source control in the following order,

  1. The latest copy of the branch is checked out from source control into the “working” folder
  2. Using the , I build a number of predefined solutions in the working folder are built.
  3. A Nant script held in the “scripts” folder is then ran which carries out the following tasks:
  4. Generate a build instance folder containing the “deployable”, “source” and “tests” folders.
  5. Run unit tests in the build instance test folder.
  6. Package all deployable assets up into the deployable folder.
  7. Deploy assets to a demo environment.
  8. Email me to let me know the build has passed(hopefully) or failed.

I’ve stuck with this same process for over a year now but noticed a few areas where things can be improved upon to save time. I’ve spent the last week or so adding some new features to an application I manage. I created a branch and setup a cruise control build as above and began work. Along the way, I created a new solution, added some existing projects from the codebase and created a few new ones. I refactored a couple of classes and moved a number of them out into another new project so they could be reused by other parts of the code base. Being a good little agile programmer, I obviously created accompanying unit test projects and also added them to the new solution.

Once I had a good local build and all tests passed, it was time for me to check my work in.

However, as I had added more solutions and unit tests to the code base, I realised I would have to amend the build scripts so the new solution would be built and the new unit test project would be tested. So prior to checking in, I had remotely connect to my build server to update the relevant Nant script and project entry in my CC.Net config file. Once I was happy the build file and Nant scripts were ready to rock, I could then go back to my development machine and check my working copy of the feature branch in.

I was finding this context switching from dev environment to build environment disruptive and more importantly, I felt it was detracting from the amount of time I could dedicate to actually develop.

The issue finally came home to me when I merged the feature branch back into the trunk and had to copy and paste the changes from feature branch scripts to the trunk scripts. This process not only held up the TTL (Time To Live) but copying and pasting is always the point where I’ll screw up and introduce an error of some description.

Does any of this sound familiar? I spoke to @jonhilton regarding this and although he uses Teamcity and MSBuild, it sounded like he’d encountered the same sort of issues and it suddenly dawned on me.

Develop The Build As Part Of the Feature

By moving as much of the build process into the Nant script and moving the the Nant script into the the branch itself, it qualifies for all the benefits all other source controlled assets do:

  • Versioning
  • Merging
  • Reverting
  • Tagging

and by keeping the Nant scripts within the development environment (see image below), I can work on them locally so no context switching to the the build machine is necessary. All you need to do then is configure the branch build in your CC.Net project entry to run the Nant script held in the build instance folder.

SolutionExplorer

Keeping the build file within the solution helps you think of the build as part of the feature and also gives you quick and easy access to the build file for when you need it.

The real benefit is realised when you merge the branch back into the trunk and the changes are automatically merged into the… you know where I’m going with this!

The last piece of the puzzle concerns building the solutions (step 2 above) as part of the build process. I now carryout the process of running msbuild against the solutions from within the Nant script itself.

2 comments:

  1. Gotta love those epiphany moments.

    My project structure these days is

    lib
    build
    src
    deploy

    This entire structure is then version controlled, msbuild script goes in "build".

    lib is especially important, I just had to dig out an old project and spent 'king ages trying to find various dependencies that weren't under version control.

    How do you handle database versioning? this is one I haven't managed to crack yet. Before now I have added a db folder to the above, but having to manually regenerate the db create scripts means I usually forget, and that folder becomes outdated/obsolete.

    ReplyDelete
  2. I have a shared assemblies folder in the root of my working copy which contains all dll's referenced by all projects. The dll's for which I have no source for, I hold in source control. All others are generated when I setup my development environment for the after initial checkout from source.

    I'll do a post on db versioning next week but it runs on quite nicely from an earlier post

    ReplyDelete