Source Code Control
Source Code Control
CruiseControl.Net Update
So, I explained yesterday how I got CruiseControl.Net installed as part of my
quest to institute Continuous Integration in my development project. After I
published yesterday's entry, I found that I hadn't done one crucial thing.
Getting The Latest Version From Subversion Before The Build
My build kept happening every time I "committed" a new version of a source
file to Subversion, but my changes weren't showing up in the CruiseControl.Net
build. I soon realized my mistake, I needed to modify the the NAnt build files
with a couple of new <target>'s, one for getting the latest version from source
control, and one for calling the "update" target and then the "build" target. I
could have just added the "update" to the "build" target, but I may want to just
"build" the current snapshot rather than always getting the latest version. So
now I have the following for my main (D:\VirtualCellar\default.build) file. I
found this page helpful in
setting up CruiseControl.Net with Subversion.
<?xml version="1.0"?>
<project name="VirtualCellar" default="build" basedir=".">
<property name="debug" value="true"/>
<property name="build.deploy" value="release"/>
<property name="build.business" value="Lorengo.VirtualCellar.Business"/>
<property name="build.business.tests" value="Lorengo.VirtualCellar.Business.Tests"/>
<sysinfo/>
<target name="build" description="compiles projects">
<nant buildfile="${build.business}/default.build" target="build"/>
<nant buildfile="${build.business.tests}/default.build" target="build"/>
<copy todir="${build.deploy}/bin" file="${build.business}/bin/debug/${build.business}.dll"/>
</target>
<target name="update" description="Gets the latest version from source control">
<exec basedir="." program="d:\program files\subversion\bin\svn.exe" commandline="update" />
</target>
<target name="buildLatest" description="Builds the latest version from source control" depends="update,build" />
</project>
|
The "buildLatest" target depends the "build" target which depends on the
"update" target. This is backwards, according to the documentation according to
the
documentation it should be depends="build,update", but it works for me.
You'll notice that I've added an <exec> task to get the latest version from
source control. This gets the latest version for the basedir and all child
folders. I also updated my other default.build files for the other projects to
do this step should I wish to only build a project.
So, I check commit these to Subversion and it fixes my problem right? Wrong!
Because the existing default.build files in the d:\build\VirtualCellar folder
don't have the new <target>s so the update never happens, I need to manually
type the "svn update" command in the d:\build\VirtualCellar folder to bring down
the latest version. In addition I also need to update the d:\program files\CruiseControl.Net\Server\ccnet.config
file to build the new "buildLatest" target. Here's the updated
ccnet.config file.
<cruisecontrol>
<project name="VirtualCellar">
<webURL>http://localhost/ccnet</webURL>
<schedule type="schedule" sleepSeconds="300"/>
<sourcecontrol type="svn">
<executable>D:\program files\subversion\bin\svn.exe</executable>
<trunkUrl>file:///D:/Svn/VirtualCellar/trunk</trunkUrl>
</sourcecontrol>
<build type="nant">
<executable>D:\Program Files\nant-0.84\bin\nant.exe</executable>
<baseDirectory>D:\Build\VirtualCellar</baseDirectory>
<buildFile>default.build</buildFile>
<buildargs></buildargs>
<targetList>
<target>buildLatest</target>
</targetList>
<buildTimeoutSeconds>300</buildTimeoutSeconds>
</build>
<publishers>
<xmllogger>
<logDir>..\web\log</logDir>
</xmllogger>
</publishers>
</project>
</cruisecontrol> |
In addition to the change in the <target> node, you'll see that I've added a
<publishers> node that contains an entry for a log directory. This is where the
resulting build log will get created. I made a d:\program files\cruisecontrol.net\web\log
folder and pointed the logdir there.
Setting up the Web
I went and setup a Virtual Directory in IIS to point to the d:\program files\cruisecontrol.net\web
folder and named it CCNET, so now when I go to
http://localhost/ccnet, I get a screen like
this

You can see here that it took me a few tries to get the build to successfully
get the latest version from source control. This entry shows that the last build
was successful, and it's been an hour since it's done another build. Remember it
checks to see if there are any changes, and builds if there are any.
You may
also notice the "Test Details" and "FxCop" links. CruiseControl.Net will
automate these for you as well. That will be my next task for CC.Net.
ThoughtWorks gives a
nice overview picture on how CruiseControl.Net works.
Unit Tests for
First User Story Complete
I've completed my
first set of Test Cases for my first
User Story. All of them pass!

I've ended up with the following two classes (Cellar & Wine). I'm satisfied
with the current implementation for the first user story, but I can already see
problems with this implementation. I need to switch focus to the Wine class and
devote some modeling time to my project. In particular how Wine objects come
into being. I think there's a WineCatalog or somesuch class in my future that
will hold all of the known wines. So that's what I'll be working on today and
hopefully publish my intial model tomorrow!.

As I said in my last entry, I wanted to begin setting up my environment for the
Virtual Cellar using Continuous Integration. A free software package that does
that for me is CruiseControl.Net
I downloaded
CruiseControl.Net version 0.6.1 and unzipped it to my D:\Program Files\CruiseControl.Net
folder.
Configuring Cruise Control
As you recall I'm using Subversion
for my source code provider and NAnt for my
build tool. At a minimum this is what I need to get cruise control working.
Editing the ccnet.config file
The default installation of cruise control comes with a D:\Program Files\CruiseControl.Net\server\ccnet.example.config
configuration file. I removed a lot of the information from this file, and
tailored it to work with
my installation of Subversion.
<cruisecontrol>
<project name="VirtualCellar">
<webURL>http://localhost/ccnet</webURL>
<schedule type="schedule" sleepSeconds="60"/>
<sourcecontrol type="svn">
<executable>D:\program files\subversion\bin\svn.exe</executable>
<trunkUrl>file:///D:/Svn/VirtualCellar/trunk</trunkUrl>
</sourcecontrol>
<build type="nant">
<executable>D:\Program Files\nant-0.84\bin\nant.exe</executable>
<baseDirectory>D:\Build\VirtualCellar</baseDirectory>
<buildFile>default.build</buildFile>
<targetList>
<target>build</target>
</targetList>
<buildTimeoutSeconds>300</buildTimeoutSeconds>
</build>
</project>
</cruisecontrol> |
As you can see, I've named my project "VirtualCellar". We'll skip the <webUrl>
entry for now, as I haven't yet setup the website. <schedule> node tells
cc.net to check for changes in the <sourcecontrol> every 60 seconds. (This
is probably too short for me, but I'll leave it set that way for now).
I've also setup the <sourcecontrol> node to use Subversion and
pointed it to my installation of the subversion program files. In addition, I
need to point to the trunk (or root) of my Virtual Cellar project in the
Subversion repository. CC.Net supports many different types of source control
programs.
CC.Net and NAnt
I next need to tell CC.Net how I plan to build my application. As you may
recall I've
installed and
configured my Virtual Cellar project to be built with Nant. I do this
by pointing to the NAnt executable (I moved it since my last installation from
d:\nant-0.84 to d:\program files\nant-0.84, I also need to check into using
environment variables rather than hard coded paths).
I need to tell CC.Net where to build the continuous integration version
of the Virtual Cellar project. When I setup Subversion, I
chose D:\VirtualCellar for "my working
copy". I don't want CC.NET to use that folder because that's *my* project and I
may have files that I'm working on that aren't checked in to Subversion. So, I
have to setup a working folder for Subversion. Normally CC.Net would run on a
dedicated Build Server, but for now I'm running it on my dev machine.
So, in
looking back at
my Subversion post, I need to create a build folder and then checkout the
latest version of the VirtualCellar project to that folder. The following box
shows the result. You can see all the work I've done so far, I have my
documentation, two projects (Lorengo.VirtualCellar.Business and Tests) along
with their associated .csproj and NAnt build files.
D:\>md build
D:\>cd build
D:\build>svn checkout file:///d:/svn/VirtualCellar/trunk VirtualCellar
A VirtualCellar\VirtualCellar.sln
A VirtualCellar\default.build
A VirtualCellar\Doc
A VirtualCellar\Doc\rup
A VirtualCellar\Doc\rup\02Elaboration
A VirtualCellar\Doc\rup\01Inception
A VirtualCellar\Doc\rup\01Inception\VirtualCellar.BusinessCase.doc
A VirtualCellar\Doc\rup\01Inception\VirtualCellar.Vision.doc
A VirtualCellar\Lorengo.VirtualCellar.Business
A VirtualCellar\Lorengo.VirtualCellar.Business\AssemblyInfo.cs
A VirtualCellar\Lorengo.VirtualCellar.Business\Cellar.cs
A VirtualCellar\Lorengo.VirtualCellar.Business\default.build
A VirtualCellar\Lorengo.VirtualCellar.Business\Lorengo.VirtualCellar.Business.csproj
A VirtualCellar\Lorengo.VirtualCellar.Business\Wine.cs
A VirtualCellar\Lorengo.VirtualCellar.Business.Tests
A VirtualCellar\Lorengo.VirtualCellar.Business.Tests\AssemblyInfo.cs
A VirtualCellar\Lorengo.VirtualCellar.Business.Tests\default.build
A VirtualCellar\Lorengo.VirtualCellar.Business.Tests\Lorengo.VirtualCellar.Business.Tests.csproj
A VirtualCellar\Lorengo.VirtualCellar.Business.Tests\CellarFixture.cs
Checked out revision 9. |
When all is said and done I now have another working copy of my Virtual
Cellar project for CC.Net in the D:\Build\VirtualCellar folder. This is what I
set as my <baseDirectory> and point to the default.build file as my <buildFile>.
The <target> tells NAnt which target in the build file to build, for now I have
2 targets, "clean" and "build" (which is dependent on "clean"). I'll be adding
more targets going forward but for now I'll use the "build" target.
And that's it! I'll save this file as ccnet.config
Running CruiseControl.Net
All that is left to do is run the cruise control server, here's the output...
D:\Program Files\CruiseControl.Net\server>ccnet
[CruiseControl Server:Info]: CruiseManager: Listening on tcp://192.168.1.100:21234/CruiseManager.rem
[CruiseControl Server:Info]: Starting CruiseControl.NET Server
[CruiseControl Server:Info]: Reading configuration file "D:\CruiseControl.Net\server\ccnet.config"
[CruiseControl Server:Info]: Starting integrator for project: VirtualCellar
[VirtualCellar:Info]: Starting integration for project: VirtualCellar
[VirtualCellar:Info]: 25 modifications detected.
[VirtualCellar:Info]: Building
[VirtualCellar:Info]: Build complete: Success
[VirtualCellar:Info]: Integration complete: 9/27/2004 7:23:25 PM
[VirtualCellar:Info]: No modifications detected.
...(more of same deleted)...
[VirtualCellar:Info]: No modifications detected.
[VirtualCellar:Info]: 1 modification detected.
[VirtualCellar:Info]: Building
[VirtualCellar:Info]: Build complete: Success
[VirtualCellar:Info]: Integration complete: 9/27/2004 7:49:37 PM
|
The first time it runs it knows that it hasn't built anything so it detects
all of the changes so far and runs the build successfully (Yeah!). I'll now go
ahead and add a new test to the CellarFixture.cs class. Here's what it looks
like in Windows Explorer with TortoiseSVN installed.

You can see that the CellarFixture.cs is flagged as up to date, here's what
it looks like after I modify it with a new test, and then save the file.

It's flagged as being different or updated. It isn't until I right+click on
the file and say "Commit" from the TortoiseSVN context menu that the file is
committed to Subversion. (Of course I've compiled and tested it on my machine
before I do this so I don't "break the build"). Once I commit my changes, Cruise
control detects the change (every 60 seconds for now), and issues the build with
another Success! As my project grows and takes more time to build, I'll probably
want to change the schedule to every hour or so...
That's it! I've got a integration server that will now build when changes to
the repository are detected. I can now continue with more development. Of course
there are other things that I'll want to add to my continuous integration
pipeline, like automagicall running NUnit (or MbUnit) tests, FxCop rules, and
eventually creating an install package. Ahh! what the future holds.
Odds and Ends - MSBuild with NAnt
In my
Refrigerators, Unit Testing and NAnt post Kirk
Maple asked about using MSBuild with NAnt, one possible solution would be to
do the following...
<target name="build">
<sysinfo />
<exec program="PathToMSBuild\MSBuild.exe"
commandline="MyProject.csproj" />
</target> |
Seeing as I didn't install the Team System Yet, I don't have MSBuild on
my machine, so Your Mileage May Vary.
I decided to install two source code control providers so that I can begin
putting my project under source code control. My initial choices for
evaluation were going to be CVS, Subversion and Source Safe, after looking at
Subversion, I see no reason to try and install CVS since it's more or less
compatible with CVS with some added functionality. Here is an interesting
comparison of
source control providers. Granted it doesn't include comparisons with
SourceGear's products or
PVCS.
Eric Sink has written on online book on
Source Control:
How To
Installing Subversion
Subversion is billed as a better version of CVS. I chose to download release
1.1.0rc3 because according to the
release notes
it allows the repository to be file system based as opposed to using
BerkelyDB. The release I'm downloading
is for Win32 and is packaged as a setup program, and basically it runs the
install and that's it.
I'm also installing TortoiseSVN
which presents a nice GUI interface (similar to
TortoiseCVS for
CVS) into Subversion. I'm installing
version
1.1.0rc2, here are the
release notes.
Configuring Subversion
The Subversion Book is an
excellent free resource for determining how to use Subversion. In addition
Mike Mason advocates setting up a
Single Repository over Multiple Repositories in subversion and also lists some
suggestions for Effective Source
Control
Creating A Repository
I'll use the command line tool to create a repository. I'll want to create
the repository using the file system rather using the BerkeleyDB structure. This
will allow me to access the file system remotely.
Adding to the Repository
After
creating a repository in the d:\svn folder, I'm
going to create a tmpdir and establish a folder layout for my new project. I
could use the
svn mkdir command if I wanted to, but since I'll be adding a few directories
I'll use the
svn import command.
D:\>mkdir tmpdir
D:\>cd tmpdir
D:\tmpdir>mkdir VirtualCellar\trunk
D:\tmpdir>mkdir VirtualCellar\branches
D:\tmpdir>mkdir VirtualCellar\releases
D:\tmpdir>svn import -m "Initial Layout of VirtualCellar Project" file:///d:/svn
Adding VirtualCellar
Adding VirtualCellar\releases
Adding VirtualCellar\trunk
Adding VirtualCellar\branches
Committed revision 1.
|
I'll now go ahead and delete the tmpdir and list the files in the repository
using the
svn list command
D:\tmpdir>cd ..
D:\>rmdir /s tmpdir
D:\>svn list -v file:///d:/svn
1 mlorengo Sep 21 12:17 VirtualCellar/
|
Checking out the project
Now that I have a project in svn, I'll go ahead and checkout the trunk to
perform some work like adding my intial RUP documentation to the repository, but
before I do that I'll use the svn mkdir command to make a Doc\rup folder under
the trunk where my Inception and Elaboration documents will reside.
D:\>svn checkout file:///d:/svn/VirtualCellar/trunk VirtualCellar
Checked out revision 1.
D:\>cd VirtualCellar
D:\VirtualCellar>svn mkdir Doc
A Doc
D:\VirtualCellar>cd doc
D:\VirtualCellar\Doc>svn mkdir rup
A rup
D:\VirtualCellar\Doc>cd rup
D:\VirtualCellar\Doc\rup>mkdir 01Inception
A 01Inception
D:\VirtualCellar\Doc\rup>mkdir 02Elaboration
A 01Elaboration
D:\VirtualCellar\Doc\rup>cd 01Inception
D:\VirtualCellar\Doc\rup\01Inception>
|
Now that I have my directory structure built, I'll go ahead and commit the changes queued thus far
D:\VirtualCellar\Doc\rup\01Inception>svn commit -m "Added rup documentation folders" |
Now I can copy my BusinessCase.Doc and my Vision.Doc documents to the 01Inception folder and add them to the repository
D:\VirtualCellar\Doc\rup\01Inception>svn add Vision.Doc
D:\VirtualCellar\Doc\rup\01Inception>svn add BusinessCase.Doc
D:\VirtualCellar\Doc\rup\01Inception>svn commit -m "Added Inception Documents to repository"
|
What's Left To Do
Now that I have Subversion setup, there are still a few more things left to
do. I'll need to work out security, so I know who's checking in what, and I'll
need to figure out the svnserve -d option so that I can pull information from
the repository remotely.
I know I promised some Use Cases and User Stories today, but it appears that
those tasks have been subverted (ouch!). I'll work on them the rest of the day
and maybe get them posted later on this evening.