Friday, April 29, 2005

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

10 comments:

Anonymous said...

Jeff,

You can easily create your continuous integration infrastructure for your MSBuild projects with Parabuild. Parabuild is a commercial continuous integration build server. It takes about 2 minutes to install on Windows:

http://www.viewtier.com/products/parabuild/index.htm

Anonymous said...

Hey Jeff

You might want to check out Team Build - the build automation server MS is shipping with Visual Studio Team System. Team Build uses MSBuild as its build engine.

Check out my blog at http://blogs.msdn.com/team_foundation/archive/2005/03/02/383479.aspx

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.
Rover said...

does continue on error for fxcop analysis task meas taht a build will brek if there are fxcop compliance issues

I want my build to break if there are fxcop errors

Jeff Martin said...

Rover,

ContinueOnError=true means that the build will NOT break if there are compliance issues, so you want to set ContinueOnError=false

Anonymous said...

Please have a look at my msbuild target

Exec Command="FxCopCmd.exe /file:$(MSBuildProjectDirectory)\SmallTestApp\bin\debug\*.exe /out:E:\Newccnet\Hpreport.xml" WorkingDirectory="C:\Program Files\Microsoft FxCop 1.36" ContinueOnError="true"


I have integrated with cruise control

Problem: Though i have marked ContinueOnError=true, my build fails.
Can u please help in this.
Thanks in advance...

Jeff Martin said...

It should not break if you have ContinueOnError="true". Perhaps it is something else breaking it? Without more information (specifically the build log), I really can't say. I would contact you personally, but you posted anonymously.

Unknown said...

Yes please i would like to send across my build and config i have done. can u please contact me..
Thanks for the help.

Unknown said...

I have sent you a mail with details attached, kindly revert on the same.
Thanks