Finally! My day-long odyssey is over. I have a full and complete and successful build!
First, let me just say, if you are doing .NET projects of any non-trivial size, you absolutely must read Expert .NET Delivery Using NAnt and CruiseControl.NET. It is absolutely one of the most well put-together, timely, and useful software books I have read in a long time. As I was reading it, literally almost page by page, I was thinking “yes, I do want to implement something like that”.
Moving on…I had dabbled in CruiseControl.Net before, got a basic build system up and running, and left it at that. However, I really just cobbled together a bunch of samples that I really didn’t understand, especially when it comes to NAnt, I just had no real clue what it was doing, or more importantly, what it was capable of. So after reading the book, I decided to put together a righteous build system today. And it took a good majority of the day to get it working right. And I still want to tweak it. NAnt is like a new toy to me now that my eyes have been opened to it’s capabilities.
I don’t mean for this to be a comprehensive tutorial or anything. For that, go get the book. Also, here are some great references:
Aaron's article helped me out with some of the more granular details that the book missed.
Also, make sure you have the documentation for NAnt and NAntContrib handy, as well as the CruiseControl.Net documentation. One thing I will say, the CruiseControl documentation on the site is not by any stretch of the imagination comprehensive. Over the couple of times I’ve set it up I’ve spent more time with Google than I have with the CCNet docs.
So my build system uses the following tools:
CCNet 0.9.2
NAnt 0.85 RC3
NAntContrib 0.85 RC3
NDoc 1.3.1
NDepend
FxCop 1.32
I’ll be adding in NUnit and NCover at some point, I’m just not ready yet. NDepend doesn’t integrate nicely, so rather than fuck with it I just used an <externalLink> in the ccnet.config to link to the generated NDepend report. It’s a hack, but it works for now, and I’m pretty much going to be the only one on the team reading the NDepend report anyway, so it’s all good.
CCNet is running as a service on my build machine. ccservice seems to be much more stable in this release than it was previously. My basic setup is to poll the VSS repository for changes every 2 minutes. When changes are found, I version the build, build it, run it against FxCop, NDoc, and NDepend, clean up the miscellaneous junk, and zip the built file and move to a versioned build archive. Additionally I have a skeleton setup for a nightly build system for debug and release builds, but I’m not ready to implement that yet, so it’s off. These do most of the same stuff, with moving files around a little differently for distro purposes. All that with a couple of xml config files. NAnt is da pimp.
A couple of snafus I ran into. The first is versioning. The <version> task is a part of NAntContrib and is very handy for managed versioning. Mine looks like this:
<version path="c:\somepath\project.versioning" startdate="08/01/2005" prefix="sys"/>
the “path” attribute basically just points to a text file. You put your desired 4 part version in it, and based on your options it increments that. I’m using the default increment system for buildnumber and revisionnumber, which is date based, so that’s why the “startdate” attribute. Build number in the default scheme is based on this date. The “prefix” attribute is the one that was the absolute bitch because even the NAntContrib docs on it are contradictory. The book tells you that the version task will store version information in the property sys.version by default. Wrong again, idiot. The documentation tells you it’s buildnumber.version by default. That may be true. I didn’t test it. I had already written the rest of my build file against sys.version, so I changed the prefix attribute to “sys.” with the period. I used the period, because the documentation says the default is “buildnumber.”, indicating that you need to include the dot. Nope. Wrong again, idiot. So it took two builds to figure it out, but the dot is implied.
The book has a real easy and practical versioning method. I don’t want to plaigiarize the whole thing, but basically after doing the version thing, you write to the AssemblyInfo.cs (or a common, shared assemblyinfo file for larger solutions) using the <asminfo> task. And don’t forget to <attrib> files before trying to write to them if they are read-only from the VSS process. Ah…attrib. I miss DOS.
Another is that the book tells you that the NDoc task for NAnt is using the same xml as generated from the NDoc GUI project setup. That’s almost true. If you open the .ndoc file you generate from the GUI in notepad and just copy the <documenters> sections that you want, that part is the same. The assembly stuff though you have to do according to the NAnt documentation. So just launch NDoc, set up the project, save the file, open in text editor, and copy the <documenters> parts that you want into the NAnt build file and you will save yourself a bunch of time trying to manually configure the build file.
My last tip is using the version property that was set from the <version> task. I use it to zip and store archived builds, like so:
<zip zipfile="C:\somepath\${sys.version}archive.zip">
<fileset basedir="c:\somepath\builds\Last-Debug">
<include name="**/*"/>
</fileset>
</zip>
My recommendation is that you break up the build file with plenty of logical tasks for ease of reading and manageability. I started with a single target and it got unwieldy in a hurry. Also take a good look through the available functionality of NAnt/NAntContrib to get a better idea of what exactly is possible. I’ve found it best to use ccnet as basically the shell and do much of the heavy lifting in NAnt. It just seems to work better that way.
The most important thing is to sit down ahead of time and plan your build solution like any other project. What do you want to accomplish? Spec it out. It will make it a lot easier to implement and stay on task as you start to really dive deep into what you have available to you. And definitely check out Expert .NET Delivery if you haven’t yet. It’s worth it.
Tags:
Continuous Integration