I have completed or at least gotten a good start with
Continuous Integration. What I have done may not be doctrine but it is what I
could find to be the simplest and cleanest way. There are in my opinion 4 main
parts you must have in order to achieve CI. First you must have a good repository,
second you need to have a development tree setup for your project, then each project
needs a build script, and finally you need to setup an automated build server.
For more on continuous integration check out Martin
Fowlers article and Jay
Flowers article.
- Repository
The repository/version
control/source code management, what ever you like to call it is the first
thing that needs to be established. There needs to be a common place where your
entire source is kept so that your build server can know where to get the
latest version (head). I choose Subversion
(svn) with TortoiseSVN. I was
using visual source safe and I was happy about this, but like my grandpa is
happy with dial-up, I had no idea what I was missing. If you are using source
safe switch now to Subversion its open source and its free you will not regret
it.
If you would like to know just
about everything a user would need to know about modern repositories go to Eric
Sink’s online book: Source
Control HOWTO.
- Creating
Development Tree
Basically the Development tree is
the folder structure/organization of your project. A good development tree is
defined by Mike Roberts as
easily inheritable on new environments, requires little maintenance, easily
maintained, supports productivity, and is consistent. I tried to follow his
guide lines in his article: How
to Setup a .NET Development Tree. I am using a refactored patterns
project I did earlier for this example. I define the trunk/root folder name to
be the same as my visual studio solution. In this folder I have 3 other folders
src, lib, and tools.
The src contains all the developer
created content need to build the solution. The lib contains all references
dlls that are needed for the project and are not built with the solution. The
tools folder will house things like NAnt,
NUnit, FXCop, and whatever else you
need to help build quality software. You can also include a docs folder to
contain the documentation. Another good source on development trees is an article
on Brig
Lamoreaux blog.
- Build Script
To
automate my builds I choose NAnt
+ NAntContrib. I save the build
script in the root of the project with the file name of [projectName].Build
and a go.bat that contains one line that calls NAnt with the build script.
@tools\nant\Nant.exe -buildfile:[projectName].build %*
> buildOut.txt
The >
BuildOut.txt saves the out put of the build result to a text file I found
this convenient to view how the build went. My build script should be made in a
way that is easily implemented, easy to maintain, and need as little maintenance
as possible. I include this as an existing solution item that way it can be
edited along with the src.

<?xml version="1.0" encoding="utf-8"?>
<project name ="nant" default ="all">
<!-- The Build Directory -->
<property name="build.dir" value ="build"/>
<!-- Define Default targets and the order they run -->
<target name="all" depends="clean, compile, run-unit-tests" description="Compile and Run Tests"/>
<!-- delete build folder, everything in this folder should be created on the build,
so it should be safe to delete at any time. -->
<target name="clean" description="Delete automated build artifacts">
<delete dir="${build.dir}" if="${directory::exists(property::get-value('build.dir'))}"/>
</target>
<!-- Compile solution with msbuild task(Only Available with NAntCOntrib)
if it is 2003 use solution task all build properties should be
set up in a new VS Automated Build configuration. -->
<target name="compile">
<!-- point msbuild to the solution file with should be at the root of your src folder-->
<msbuild project="src\Patterns.sln">
<property name="Configuration" value="Automated"/>
</msbuild>
</target>
<!-- RunUnit tests -->
<target name ="run-unit-tests">
<!-- Creates Nunit Reprot Directory-->
<mkdir dir="${build.dir}\test-reports"/>
<exec program="nunit-console.exe" basedir="tools\nunit"
workingdir="${build.dir}">
<!-- The dll that contains your test that
should now be in the build folder -->
<arg value="Strategy.Test.dll"/>
<!-- Location and name of the NUnit test report -->
<arg value="/xml:test-reports\UnitTests.xml"/>
</exec>
</target>
</project>
In side VS I set up a new visual
studio build configuration called Automated.
Automated is basically a copy of the default configuration Release but I changed the folder it
builds to be ..\..\build\.

- Build Server
The
final step is implementing your build server. I have heard of people just
using scheduled tasks for this but that doesn’t sound very useful. I
wanted the build done when some one commits a change to the repository.
For this I used CruiseControl.NET.
CruiseControl.NET is an
Automated Continuous Integration server, implemented using the Microsoft
.NET Framework. It works with majority of the source code management (SCM)
tools out there and more importantly it works with subversion. The
installation was simple just download and run the MSI but the
configuration can be a little difficult because of the flexibility
available. To get it running you need to edit the ccnet.config.
<cruisecontrol>
<!-- Each Project needs the following setup -->
<project name="Patterns">
<!-- The Working folder/checked out
folder for the project on the server -->
<workingDirectory>H:\MyApps\Patterns</workingDirectory>
<!-- sourcecontrol setup -->
<sourcecontrol type="svn">
<!-- URL to the project in the repository -->
<trunkUrl>http://www.myrepos.com/myapps/Patterns/</trunkUrl>
<executable>D:\Program Files\Subversion\bin\svn.exe</executable>
<!-- The Working folder/checked out
folder for the project on the server -->
<workingDirectory>H:\MyApps\Patterns</workingDirectory>
</sourcecontrol>
<!--Build task-->
<tasks>
<nant>
<!-- Nant EXE for project -->
<executable>H:\MyApps\Patterns\tools\Nant\nant.exe</executable>
<!-- where the build file lives -->
<baseDirectory>H:\MyApps\Patterns</baseDirectory>
<buildArgs></buildArgs>
<nologo>false</nologo>
<buildFile>Patterns.build</buildFile>
<buildTimeoutSeconds>1200</buildTimeoutSeconds>
</nant>
</tasks>
<!-- reporting information -->
<publishers>
<merge>
<files>
<!-- Location of Unit test reports -->
<file>H:\MyApps\Patterns\Build\test-reports\UnitTests*.xml</file>
</files>
</merge>
<!-- create the log files used by the CruiseControl.NET Web Dashboard -->
<xmllogger logDir="D:\Program Files\CruiseControl.NET\server\Patterns\BuildLogs" />
<!--default statistics for capturing during the build process.-->
<statistics />
</publishers>
</project>
</cruisecontrol>
After that just edit the project,
commit the changes, and watch the dashboard build report.