Friday, April 29, 2005

XML and Blogger.com

Wow, blogger.com doesn't like XML. It doesn't support the code or pre tag at all. And in the XML file example below, the first two elements should be...

Project DefaultTargets="Build"

and

Target Name="Build"

For some reason it cut the words Project and Target off.

Continuous Integration with Visual Studio 2005

Working in a beta version of Visual Studio 2005 presented some challenges when attempting to use continuous (a.k.a. continual) integration. Several of the tools are not yet available in .Net 2.0 versions. And nAnt, the backbone of automated building, doesn't understand VS 2005 project or solution files. You could build your build file by hand, but since laziness is a vitue in programmers1 , I don't want to do that. I am going to create a series of articles covering CI with .Net 2.0. As I learn things, I will share them with you.

Automated Building

The backbone of continuous integration is automated building. This is the process that the CI server kicks off to build your code, run automated tests, document, deploy and whatever else you want to happen. Most systems currently use nAnt, which is a very powerful build system. When I started examining continuous integration, I downloaded nAnt and started testing with it. I quickly found that it does not understand Visual Studio 2005 solution files. I did not want to have to maintain two files everytime I added a new file to a project, so I looked at MSBuild, which ships with the .Net 2.0 framework. MSBuild not only understands VS 2005 solution files, it also allows you to execute different tasks and develop your own tasks just like nAnt. And since it comes with the framework, you do not have to have Visual Studio on your build machine.

If you just want to build your project and not execute any tasks, you simply execute MSBuild in your project's directory. If you run it with no parameters, it defaults to the .csproj file in the directory. If you have a solution with multiple projects, you can pass the solution filename as a command line parameter.

c:\buildsrc\TestSolution>MSBuild TestSolution.sln


This is just a very basic example of what MSBuild can do. You can pass properties on the command line also, so if you want to switch between Debug and Release, you can pass which configuration you want to use.

c:\buildsrc\TestSolution>MSBuild TestSolution.sln /p:Configuration=Debug


You could create a complex command line to pass to MSBuild and maintain it in your continuous integration configuration, but it is easier to create a .msbuild file for your project. This file can be used by MSBuild to not only build your project, but also to execute other tasks such as automated testing and documentation. A .msbuild file is a simple XML file. Here is a sample file.


< name="Build">
< !-- Clean, then rebuild entire solution -->
<
MSBuild Projects="Project.sln" Targets="Clean;Rebuild" />

< !-- Run nUnit-->

< !-- Run FxCop analysis -->
< command="FxCopCmd.exe /file:\buildsrc\Project\bin\debug\Project.dll /out:\buildsrc\Project\Project.FxCop.xml" workingdirectory="\buildtools\FxCop" continueonerror="true">


< !-- Run nDoc-->

< command="ndocconsole.exe \buildsrc\Project\bin\debug\Project.dll -documenter=MSDN -OutputDirectory=\buildsrc\doc\Project -OutputType=Web -Title=Project" workingdirectory="\buildtools\nDoc\bin\.net-1.1" continueonerror="false">

< /Target>
< /Project>

(Excuse the spaces between the <>

This file builds the solution (which includes two projects), runs my nUnit tests (outputting the results to XML for the continuous integration server), runs FxCop analysis (outputting the results to XML for the continuous integration server) and runs nDoc to document the code. The ContinueOnError property you see tells MSBuild whether or not to fail the build if the task returns an error code.

You must setup your continuous integration server to run the command line...

MSBuild TestSolution.msbuild


I am using CruiseControl.Net as my CI server. One thing you must do with ccnet is use the command line builder task. There is a MSBuild builder task in development, so as soon as that comes out, I will switch to it. The one drawback to using the command line builder is that it does not pass the build label to MSBuild like it does with nAnt. This limits the ability of the build process to use the build label in the version number. I have written a MSBuild task (I'll cover that in another article) that generates an AssemblyInfo.cs file so I can generate the version number at build time. However, there is no way in ccnet to pass it to the command line builder. That has been my biggest complaint about ccnet. Obviously, the build label is stored somewhere because it passes it to nAnt, why not make it available via an environment variable or some other method so I can access it from MSBuild? Hopefully the MSBuild builder type will fix this problem. For now, I just have my version information hard coded. Nothing has gone to production yet, so it's not an issue at this time.

I am still learning the powers of MSBuild. I believe it will soon be comparable to nAnt in features. The MSBuild team is using Scrum as their development methodology and you can read Chris Flaat's (MSBuild team member)blog about what is going on with the project.

1 Larry Wall, Programming Perl, O'Reilly & Associates, 1991