Using MSBuild to create a deployment zip

Automated builds are one of the core fundamental musts for software development. However, your build doesn’t just have to build the solution and execute your unit tests. For IronEditor, my build also creates two zip files. One zip is the output from the build for archiving purposes, the second is my deployment zip – the zip which actually gets pushed up to CodePlex containing only the files required by the application. In this post, I will cover how you can get MSBuild to zip your build output.

To use zipping functionality within your build scripts, you need to use the MSBuild Community Tasks which is a great collection of MSBuild extensions and a must if you are using MSBuild.

In order to zip your files, you need to specify which files you want to zip. In the script below, I create an ItemGroup called ZipFiles, this includes all the subdirectories (**) and files (*.*) from my Release directory which is my build output folder. I also specify that this group should not include any other zip files. I then create a Builds directory if it doesn’t already exist. Finally, I use the Zip task, passing in my ZipFiles ItemGroup which the task uses to know which files to include.


       ZipLevel=”9″ />

The most important property is the WorkingDirectory, this is the root directory where all the files you want to exist live. If you don’t have this set correctly, you will have the additional directories in your zip file which are navigated in order to get to your actual files and just looks rubbish.

My deployment zip also looks very similar and is executed after the above target. The only different is that I individually specify which files and directories to include. For some directories, such as Config, I still include all sub-directories and files it contains as they will all be relevant and required.


       ZipLevel=”9″ />

One thing which tripped me up was that while my ItemGroup was created within a target, it actually has global scope. As such, you need to call the two groups within the two different targets something different.

Once my script has executed, I have two zip files created – one containing everything, the other ready to be released on CodePlex.


Technorati Tags: ,

Overriding MSBuild variables via command line options

While working on a build script for the Pex Extensions project, I wanted to be able to specify the version of Pex which the project was built against for use within the AssemblyInfo and file names. This build script is being executed manually in order to create all the zip files to upload but I didn’t want to have to manually edit the script to set the value. I wanted to provide the version when I executed MSBuild via the command line as a command line argument.

After a bit of searching on MSDN, I found that you can override any variables created within the PropertyGroup. At the top of your build script, you generally define your variables within the PropertyGroup to specify paths, versions etc. Within my build script, my PropertyGroup looked like this:


Using the /p: command line switch, I can override the PexVersion property by executing the script as follows:

> msbuild Pex.msbuild /p:PexVersion=0.6.30728.0

If I forget to set the argument, the value set within the script will be used.

Technorati Tags:

Continuous Integration Builds for CodePlex Projects

As many of you might be aware, I maintain the IronEditor project on CodePlex.  I like CodePlex, I find the wiki and issue tracking to be useful, but I find the directory structure and searchablity of projects on the site to be most useful. However, the one thing which I wish it could offer, and this goes for Google Project Hosting as well, is a continuous integration server. I would like to know that after I have pushed my changes to CodePlex, that it does actually compile.

As I’ve posted before, I run TeamCity on my home machine as it is free and easy to configure. As TeamCity can connect to Team Foundation Server (what CodePlex runs under the covers), I decided I would just be able to connect to the CodePlex servers and threat it like any normal source control system.

Sadly, I was wrong. When I tried to connect, I found the following (extremely helpful) error:


If anyone knows the reason why this failed, please leave a comment.

However, all is not lost! CodePlex have created the SVNBridge, a small application which runs on your local machine, or in this case your CC server. This translates all SVN commands into TFS commands, the result is that you can connect to CodePlex using SVN clients, one of which is TeamCity!

Connecting TeamCity via SVNBridge to CodePlex

SVNBridge is a single executable. It lives in the system tray and listens for communications on a particular port, in my case 8081.


In order to connect to SVNBridge, and as such your CodePlex project you must use a particular URL.  The URL is your SVNBridgeAddress/YourCodePlexServer/YourProject

For example, IronEditor lives on and in order for me to connect via the bridge my URL would be:


With my setup, I simple wanted to be able to click run and TeamCity go off, download the latest code from TFS, build my solution and execute my unit tests again just to be sure I haven’t broken anything (or in my case simply forgot to upload the latest code changes).

In order to connect TeamCity to CodePlex, you simply need to use the Subversion VCS settings and point it at your SVNBridge. Below, are my settings for IronEditor. The username and password you need to use to connect are your website login details.


On TeamCity’s dashboard, I now have my new CodePlex build along with my local IronEditor build, both run the MSBuild script, they just pull the sources from different locations. After I have pushed my changes to CodePlex, I manually click run, and off it goes. The reason I don’t have it manually checking is because it’s rare I push changes to codeplex and as such I’m happy to be in control of when it happens.


TeamCity is now happily talking to my CodePlex repository, building as and when asked. If you happen to have a spare server, or a windows home server, then you could run this setup from there, have it automatically check for modifications with all the developers on your project benefiting.

Technorati Tags: , , ,

MSBuild – Build Visual Studio 2008 solution and execute Unit Tests

Previously, I have spoke about how you can update your AssemblyInfo file using MSBuild. However, I haven’t spoken about the very basics – how to build a Visual Studio solution and execute your unit tests.

MSBuild is a very interesting build scripting language, out of the box it includes a set of standard tasks which you can use based on your requirements, such as creating a directory or copying a file in order to correctly build your project. I also take advantage of the MSBuild community task project, while it hasn’t been updated in a while, the tasks work perfectly.

Below is the basic MSBuild script.

DefaultTargets=”Test” xmlns=”″>
        <MSBuild Projects=”TeamCityBlogExample.sln” Properties=”Configuration=Release” />

        <NUnit Assemblies=”TeamCityBlogExample.TestsbinReleaseTeamCityBlogExample.Tests.dll”
               ToolPath=”C:Program FilesTestDriven.NET 2.0NUnit2.4″ 
               OutputXmlFile=”NUnitResults.xml” />

Within the project section at the top, I set the default target to Test. This is the target which will be executed first, the Test target then has a DependsOnTarget attribute which enforces that the build must be done before we test.

On line 3, I import a reference to the MSBuild community tasks so I can access all of the custom tasks included – such as NUnit.  Next I define my build target, within this I define the solution I want to build and the configuration. To execute my unit tests, I use the NUnit task from the community task project, this takes a list of all the assemblies which we need to run, define if a test fails wether it should fail the build and finally tell it where NUnit lives on the local machine.

Now, the script can be executed by a build system, such as CCNet or TeamCity, or from the command line using the msbuild.exe command and build your solution and execute your unit tests.

Download script:

Technorati Tags: ,

CCNet, MSBuild and MsBuildTasks

Recently, I setup a local CruiseControl.NET Server for a project I’m working on. In order for CCNet to execute a MSBuild project, you need to configure CCNet.config, this is found in your installation directory for the server – in my case ‘C:Program FilesCruiseControl.NETserver’.

The basic structure for a ccnet project would look something like this. You have a project and within that you have a series of tasks (you can find a more complete sample on the documentation page –  These tasks are CCNet tasks, built into the server to use as part of your build process. In my example, I’m using the MSBuild task to build MyProject.sln.

        MyProject.sln        /noconsolelogger /p:Configuration=Debug
        C:Program FilesCruiseControl.NETserverThoughtWorks.CruiseControl.MSBuild.dll



At this point, my project happily building, next I want to execute my NUnit tests and have my results displayed in the web dashboard.

After my first attempt of using the CCNet NUnit task, the unit tests failed because I was referencing a file (naughty I know) on the disk and as NUnit shadow copies all of it’s assemblies so they aren’t locked I realised I needed to disable Shadow Copy. A very simple task I thought, NUnit accepts a parameter on the console application for this.

A quick look at the NUnit CCNet Task page and I was faced with a bit of a problem. The NUnit task looks like this:



Notice, no element for setting the command line properties!!! Such a core feature I can’t believe it was missed. After a quick chat with the build manager at Red Gate, he pointed me towards and their NUnit Task. This is a set of MSBuild Community Tasks which you can use as part of your msbuild script to perform various tasks – such as executing nunit tests.

Creating a MSBuild Script using MSBuild community tasks

MSBuild is a build system which defines how to build your .Net solutions. The script is based on xml, the basic outline is below:″>


As part of this I am importing the MSBuild community tasks targets file, this will allow me to use the tasks later on. Notice at the top within the project element, I have defined a DefaultTarget (DefaultTargets=”Test”). As far as I can tell, this is the target which will be executed first when the script is built, this will make more sense in a moment.

Once we have this in place, we need to define some tasks. In the example below, the first target is the build. This target has a single task, run the MSBuild task against my solution with the configuration as release. This will execute MSBuild to compile my application – excellent!

After the build target, we have the ‘Test’ target, as defined in the DefaultTargets this is what is executed first.  I then use the DependsOnTarget to define the task which should be run before the current task, the ‘Build’ target could also depend on other targets. As a result, everything gets built in order based on their dependencies. This Test Target executed NUnit and runs the unit tests for MyProject.Tests.dll and outputs the results to nunit-results.xml. The continue on error property defines if the build should fail if a test fails – which it should!


           OutputXmlFile=”$(Logs)nunit-results.xml” />

The most important line for me was the ability to DisableShadowCopy as a property, the reason why I had to use the community tasks.

By using this, I can now have CCNet run this MSBuild script which in turn builds and executes my unit tests. Hopefully, this gives you a very quick overview of how to use the MSBuild community tasks. In a later post, I will explain my complete MSBuild script for my current project and how I utilise the community tasks.


There are more advanced ways of managing your ccnet config and your MSBuild scripts, if you are managing a number of different projects I would really recommend you investigate different ways of managing the config.  This post was just how to manage your first project.

Technorati Tags: ,