As I said in part zero I wanted to stay away from philosophy, but I want to talk about that last sentence a little more. Trying to address multiple needed outcomes/deliverables in a single container approaches a worst practice. You will need to check for and track multiple fatal failure conditions and conversely, multiple success conditions, and you're going to fail trying. It's not worth it. You can't effectively serve two masters at the same time - listen to what Yoda said in the movies. A successful msbuild has just one required output, everything else is frosting. Take your uber-complex build monster script, break down the requirements until you have a list of the prizes you need and silo each one into its own build. Capisce?
Back to our build script. Remember wikipedia's definition of CI from part zero of this series?
"small pieces of effort, applied frequently"Identify your prize, break it down to the smallest piece of discrete effort, and write it so you can apply it frequently. That's the magic formula. In fact, 99% of the build scripts I write can be boiled down to the same skeleton over and over. Cleanup, build (clean) and deploy (to Test). Step 1, Step 2 and Step 3. Everything else in your build is window dressing and any failure of those three steps is fatal.
If other factors come into play, such as multiple environmental targets in a single build (deploy to Test, QA, Staging, offsite tape and burn to a DVD gold master), while I may pragmatically add an extra piece or two at first, it doesn't take very much to push me into cutting one build into multiple builds and chaining them together in some fashion.
Here's a molecular build script - under normal circumstances you don't want to break it down any further than this, and conversely you don't want to get too much more complicated than this. If you're deep in a thorny issue, you happen to step back and take a look at your creation and you don't recognize your msbuild script having a direct, familial relationship with the Clean, Compile, Deploy pseudo-code skeleton below, then you probably made a left turn at Albuquerque along the way and some refactoring needs to occur, perhaps along the lines of creating multiple builds out of your problem build.
Starter stub skeleton of 99% of my build scripts:
<?xml version="1.0" encoding="utf-8" ?>
<Project DefaultTargets="Publish" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="MasterBuild" DependsOnTargets="MasterClean">
<MSBuild (compile) Actions/>
<Target Name="Publish" DependsOnTargets="MasterBuild">
For troubleshooting purposes, I'll leave three manual cmd files committed into source control in the root of each project; one to kick off the cleanup, one to kick off the compile (which has a prereq of cleanup) and one to kick off publish (which has a prereq of compile, which has a prereq of cleanup - you get the idea). Here's the meat of the Publish.cmd I use in a .Net 4.0 project for instance -
%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe master.build %* /t:Publish %*
Very occasionally developers get some use out of them, but they are really for me when I'm initially setting up a build and troubleshooting build issues, build server/CI system issues or when I'm doing maintenance on a build.