After deploying Team Foundation Server 2008 in late 2008, the project’s second phase was intended to implement Team Build to automate builds and establish a continuous integration process for our key projects. At the time, the initial investigation work determined this to be all too hard, which is unfortunate because I’ve been doing the builds for our team ever since!
With our first-stab process templates and first-stab branch structure now being revised, and with Team System 2010 due any day now, I decided to review what “too hard” really meant and see for myself what it would take to get the 2008 build server running. In our case, we’re not only dealing with SharePoint builds and the need to output a .wsp/.cab solution file but a VS solution structure first established in 2006. One of our projects also builds a deployment (.msi) file.
Although I have yet to get the solutions proper tweaked and loaded up, I have got a relatively simple MSBuild-based SharePoint solution building, batch file post-build events and all. This post is a summary of my notes and findings from my efforts to get this working.
Andrew Connell has a detailed post on how to get MSBuild playing with MakeCab.exe, so I’d recommend starting there if you don’t have the MSBuild bits in place already. From that point I largely followed Jeremy Jameson’s advice to get the .targets and .ddf files working across desktop builds and TFS Build. For more information about MakeCab and DDF files, I highly recommend you read the MakeCab documentation linked from my earlier post.
Relative Paths
Perhaps most critically, note Visual Studio and TFS will build your source from different locations. This rules out using absolute paths in any of your scripts or things will break; you also need to be very careful with relative paths because even that old stalwart, \bin, doesn’t exist in the TFS Build environment (it instead uses \binaries).
What this means is relative paths are acceptable but you do need to suck them out of the environment variables/macros set by Visual Studio/Team Build—primarily $(OutDir) or whatever works best for you.
OutDir Cleanup
$(OutDir) may include spaces and will likely include a trailing slash, which needs to be cleaned up by adding quotes to avoid issues with spaces and removing the trailing slash before it can be supplied to MakeCab. I added this to the PropertyGroup element in my .targets file:
<QuotedOutDir>"$(OutDir)"</QuotedOutDir>
<QuotedOutDir Condition="HasTrailingSlash($(OutDir))">"$(OutDir)."</QuotedOutDir>
The property is subsequently supplied in the target:
<Exec Command="$(MakeCabPath) /F $(DDFName) /D CabinetNameTemplate=$(CabinetOutputFileName) /D Out_Dir=$(QuotedOutDir)" />
Remember, any changes to the .targets file will not be detected until the .csproj file is unloaded and reloaded (right-click in Visual Studio).
DDF and .Option Explicit
The Out_Dir parameter I supply to MakeCab (or rather the .ddf file, more precisely) is a custom variable unknown to MakeCab. With .Option Explicit enabled, you would normally be required to include a statement like this:
.define Out_Dir=
My understanding is MakeCab doesn’t support this, however, and .Option Explicit must therefore be turned off or you'll end up with an error like this:
ERROR: Option Explicit and variable not defined: OUT_DIR
Reference Other Projects and .Set SourceDir
To get the assemblies and debug symbols from the bin directories in your other projects to the deployment project, it’s easiest to to have the deployment project reference those projects; the DLLs and pdb files will then be copied to the deployment project’s bin directory—which is also the value of $(OutDir).
Instead of then referencing these files using a long path in the .ddf, they can now be referenced simply by name. You’ll first need to configure the SourceDir in the DDF, however before resetting it for the remaining files:
.Set SourceDir=%Out_Dir%
MyControls.dll
MyControls.pdb
.Set SourceDir=
Dummy Code File
I make use of a dedicated class library project responsible for wrangling the MSBuild bits, post-build events, and to otherwise contain all the SharePoint solution and feature bits. As a class library this project wants to compile and output an assembly but with no source code in the project, TFS Build will throw up a compiler error (everything will work fine on the desktop, however):
CSC(0,0): error CS2008: No inputs specified
To work around this, add an empty .cs file to the project (it’s a hack).
Long File Paths
Windows’ own maximum path length rules will kick in once you hit 259 or 260 characters. If you’re already working in a deep branch with a matching file system path structure, Team Build will likely cause you problems when it starts shifting sources into is own working directories below C:\Documents and Settings\{service}\Local Settings\Temp\. Consider the changes suggested by Aaron Hallberg to work around this problem.
Good luck!