maandag 30 juni 2008

New Layout

I've changed the layout of my weblog, I hope you like it.

If you have any remarks regarding the layout, if you don't find it readable, if you miss something, please let me know.

vrijdag 13 juni 2008

Setting Up Continuous Integration
Part II: configuring CruiseControl.NET

Now that we've created our buildscript in part I, it's time to set up the configuration file for CruiseControl.NET


The ccnet.config file and multiple project-configurations

The tasks that CruiseControl.NET should execute for your project, are configured in the ccnet.config file.
The ccnet.config file can contain multiple project configuration blocks. However, I like to have each project-configuration in it's own, separate file. In my opinion, this is much more manageable.

In order to put each project-configuration in its own XML file and import it in the ccnet.config file, you can make use of DTD entities to substitute constants with the contents of other XML files.
This is how I've done it:

<!DOCTYPE cruisecontrol [
<!ENTITY project1 SYSTEM "file:D:\folder\project1_ccnet.xml.config">
<!ENTITY project2 SYSTEM "file:D:\folder\project2_ccnet.xml.config">
]>

<cruisecontrol>

&project1;
&project2;

</cruisecontrol>

The above piece of code makes sure that the &project1 and &project2 'placeholders' are replaced with the content of the project1_ccnet.xml.config and project2_ccnet.xml.config files.

I just saw that CruiseControl.NET 1.4 has a new approach to accomplish this, however, I haven't tried it yet.

The CC.NET config file

The CC.NET config file is in fact very simple. You just have to put the Tasks that you've defined in your MSBuild file in the CC.NET config file.
Your CC.NET config file could look like this:

The above configuration file is by all means not complete; I've kept it simple, and left out some tasks. However, you should have an idea :)

MSBuild doesn't support my sln file format

The reason why I specify which executable must be used by msbuild, is very simple:
My project is written in VS.NET 2008, but targets the .NET 2.0 framework. So, by default, CC.NET will use the MSBuild program that has been delivered with the .NET 2.0 framework.
This results in an error: MSBuild doesn't recognize the VS.NET 2008 solution file format, and will stop with this error:

Solution file error MSB5014: File format version is not recognized. MSBuild can only read solution files between versions 7.0 and 9.0, inclusive.

This is offcourse due to the fact that the MSBuild that is used by VS.NET 2005 doesn't know anything about the solution file format that is used by VS.NET 2008.
You can solve this issue by specifying that CC.NET should use the MSBuild executable that can be found in the directory of the .NET 3.5 framework.

The MSBuild XmlLogger Issue

It is possible that CruiseControl.NET will not be able to execute your project, because CC.NET can't find an appropriate XmlLogger.
In this case, you'll find the following error in the CC.NET logfile:
Cannot create an instance of the logger. Could not load file or assembly 'ThoughtWorks.CruiseControl.MsBuild.dll' or one of its dependencies. The system cannot find the file specified.

You can solve this problem by placing the XmlLogger for MSBuild (you can find the dll here in your project working directory.

zaterdag 7 juni 2008

Setting Up a Continuous Integration process using CruiseControl.NET and MSBuild.
Part I: creating the MSBuild build script

Intro

I’ve been struggling lately to get a new project that I’ve started at work, under Continuous Integration.
Although I’ve used CruiseControl.NET & NAnt in my previous project for CI purposes, things didn’t go so smooth now ...

In my current project, I’m using Visual Studio.NET 2008 and targetting .NET 2.0.

Now, I wanted to use MSBuild for the build process and that’s where it all started.

I had to spent some time searching on the Net in order to get everything working like I wanted. It seems that there’s no single source of documentation for MSBuild & CC.NET which addresses all the problems that I’ve encountered.
So, the intention of this article, is to help other people setting up a CC.NET environment with MSBuild, and it will also serve as a reference for me, so that I can grab back to it when needed. :)

Requirements

What I wanted to achieve, is very simple:

I have a build machine where CruiseControl.Net is installed. This machine is already used for another project of mine for which I’m using NAnt for the build process.

The new project that I’ve started, is being developped in VS.NET 2008, targets the .NET 2.0 framework and is under SourceControl via Visual SourceSafe.

I wanted to have a CI process that regularly looks in VSS and, when something has changed, performs the following tasks:


  • Make sure that the latest buildscript will be used

  • Clean the source directory

  • Get the latest version of the codebase out of Visual SourceSafe

  • Build the entire codebase

  • Execute the unit tests that I have using NUnit

  • Perform a statical code analysis using FxCop


The MSBuild build-script

In order to automate all the steps above, I needed to have a build-script first which I can execute using MSBuild.

Such a script is also handy when the application you’re building consists of numerous VS.NET solutions; instead of opening each solution separately in Visual Studio, compiling it, opening the next solution ..., you can build the entire codebase using a single command line.
This is quite handy and productive, I can tell you :)

For every ‘task’ (clean source directory, get latest, build codebase, etc… ) that I want to execute, I’ve created a Target in the build script.

A first little problem I encountered was that MSBuild doesn’t contain any tasks that would allow you to get a latest version out of VSS, run NUnit unit-tests or perform a code analysis with FxCop out of the box.
Fortunately, there exists an open source project called the 'MSBuild Community Tasks Project' which contains additional tasks that can be executed by MSBuild. This means that you don’t need to write your own MSBuild Tasks.

Skeleton of the buildscript

Before creating the Targets, I’ve defined a few properties which I will use in all the tasks:


I define the working directory (where my source can be found) as the builddir, and a directory where the assemblies that have been build should be placed (outputdir).
Next to that, I also have an artifactsdirectory where the results of the unittests and code analysis will be put.

The last line in the above code is necessary so that we can use the additional MSBuild Tasks that can be found in the MSBuild Community Tasks Project.

Now, we can start creating our 'Targets'.

Clean Target

I want to have the possibility to start from a 'clean sheet', so I really need a Target which justs deletes everything that can be found in my builddir and outputdir.
This Target is very simple; you just have to make use of the Delete Task:

Getlatest Target

In order to get the latest version of the source out of SourceSafe, I’ve created the following step:



Here, I just make use of the VssGet Task that is part of the MSBuild Community Tasks project.
Also, notice that this Target depends on the createdirs Target; this means that, when you execute the getlatest Target, the createdirs Target will be executed before the getlatest Target is executed.

The createdirs tasks looks like this:

BuildAll Target

This is the first target where I’ve had some issues, although it’s task is very trivial:
Compile and build everything that can be found in the $(builddir), and make sure that the assemblies that have been built are placed in the $(outputdir).

It seemed very easy to do, since I found out that MSBuild.exe (which is the program I use to compile the code) had a property OutputDir. So, it would be fairly easy to set this property to the $(outputdir) variable.

Alas, to no avail. My assemblies were never copied to the output-directory. Eventually, I discovered that there also exists an OutputPath property, so I tried it. This seemed to work.
So, the buildall Target looks like this:

Offcourse, you can put multiple solution files in the Projects attribute of the MSBuild Task.
You’ll have to separate the sln files with a semicolon.

NUnit Target

This Target is quite simple:

With this Target, I run the NUnit tests that have been written in my test assembly. (I tend to name all my Test-assemblies .Tests.dll).

The results of the unit-tests procedure are placed in the artifacts directory as an XML file. In this way, I can easily incorporate the test-results in my CC.NET report (more on this later).

FxCop Target

This one was a bit cumbersome.
I started out writing this Target with the FxCop task that can be found in the MSBuild Community Project; it looked like this:


The reason why I do not apply the output XSL stylesheet, is very simple: I want CC.NET to display the results on the Dashboard, so CC.NET should read the XML file, and apply the XSL stylesheet.

Now, this Target just worked fine on my development box. However, on my ‘build server’ *ahum* (my previous dev Workstation), I couldn’t get it working.
On the build machine, I constantly kept getting errors.
Apparently, msbuild was trying to locate FxCop in C:\Program Files\Microsoft FxCop 1.32, but I don’t have this old version of FxCop installed.
I’m using FxCop 1.36 beta instead.

Therefore, I eventually opted to put the path where FxCop is installed in my %PATH% environment variable, and decided to use the Exec Task so that I could call the fxcopcmd tool:

In order to keep my build script a bit readable, I’ve created an ItemGroup in where I define all the command-line arguments that I want to pass to FxCopCmd.exe.

By default, the items that are defined in an ItemGroup will be concatenated with a semicolon. This is something I do not wanted offcourse, since command line arguments should be separated by a space.
It is easy to define that the items should be separated by a space:

@(Args, ' ')

There’s a litle sublety with the Exec command however: it doesn’t work well when you have a commandline argument that is a path which contains a space. You should escape such paths with quotes, but I haven’t succeeded in getting it to work with MSBuild yet ...


Executing Targets via MSBuild

Now that we’ve defined all the Targets, we need to see if they work offcourse.
Executing a Target is fairly easy:

Just open up a VS.NET command prompt (or open a regular command prompt and make sure that the path to the MSBuild.exe utility is in your path environment variable), and navigate to the location where your msbuild build-script is located.

Then, you just execute MSBuild, make sure that your build script is used, and tell MSBuild which target he should execute. You can also override the default values of the parameters (like $(outputdir) ) that we’ve defined in our script.

For instance:

msbuild myproject.msbuild /t:buildall /p:outputdir=r:\myproject\release /p:buildmode=release

I think that this is enough text for today.  I will soon post a subsequent article in where I’ll explain how to use this script in CruiseControl.NET.