Contact Craig Contact Craig
Show Changes Show Changes
Edit Edit
Print Print
Recent Changes Recent Changes
Subscriptions Subscriptions
Lost and Found Lost and Found
Find References Find References
Rename Rename
Search

History

6/8/2006 2:01:05 PM
-69.48.29.204
6/24/2005 12:10:09 PM
CraigAndera-68.10...
6/24/2005 12:36:50 AM
-203.199.49.78
6/24/2005 12:36:29 AM
-203.199.49.78
6/17/2005 7:20:03 AM
CraigAndera-128.9...
List all versions List all versions
Cruise Control Directory Hierarchy
.
Summary
Note
These instructions are valid for CruiseControl version 0.6. The latest versions of CruiseControl work quite differently, and don't have the problems addressed here. Primarily, all the various web applications are no longer necessary, as the webdashboard takes care of everything. See the CruiseControl website for details.

I recently took on the role of buildmaster for FlexWiki. Having had some good experiences with CruiseControl.NET, I set out to use it to configure a ContinuousIntegration server. As I sat down to work out the configuration, I realized that the out-of-the box directory structure of CruiseControl doesn't make a lot of sense in the face of multiple projects. That's an issue for FlexWiki, because while today we build all the web-related pieces as a single big package, at some point I want to link in my FwContrib pieces, and it doesn't make sense to trigger a build of the web engine just because I change something in FlexWikiPad.

So why do I say the default configuration of CruiseControl doesn't make sense? Here's the directory layout you get when you unzip the ccnet package:

  <installdir>
    server
    web
      log
    webdashboard

For brevity, I've omitted the uninteresting directories, like the web\bin directory.

Here's what each of these directories does:

Directory Purpose
<installdir> Root of the installation tree. Holds no important files.
server This is where the build service executable lives.
web The website that displays the results of the builds.
web\log Where the logfiles that hold the results of the builds are kept.
webdashboard The website that ties together all the projects the build server is managing.

You'll note that the out-of-the-box configuration assumes that you'll be building only one project. However, ccnet version 0.61 (current as of this writing) supports building several - all you have to do is put multiple <project> entries in the ccnet.config file.

Another problem with this configuration is the way the directories are located relative to one another. For example, since the build service that produces the log, it either needs to use an absolute path or ".." somewhere. I don't care for that very much. Particularly, I think absolute paths are to be avoided, since it makes it hard for me to hand the build system to someone else to run on their computer.

In the end, I came up with the following structure:

  <installdir>
    server
      Project1
        web
          log
        build
      Project2
        web
          log
        build
    webdashboard

The big change here is that I've moved all the project-specific stuff to be children of the server directory. This includes the web directory, which, after all, could be configured differently for each project that we build. For example, Project1 might have custom settings to enable code coverage analysis, and Project2 might have FxCop reports disabled.

You'll also notice that I've added a build directory to each of the projects. As you might have guessed, this is where I do each project's build. By putting it here, as a descendant of the server directory, I can have my build script write all its extra output (nunit reports, code coverage, etc) to a directory relative to the project root, and then easily use relative paths like Project1\build\reports in the <merge> section of my ccnet.config file.

I generally like to have my build website URLs reflect this hierarchy as well. So I'll have one top-level virtual directory called something like "builds". I map this to the webdashboard directory, so that someone can surf to

 http://pluralsight.com/builds/

to see the status of and get links to each of the individual projects. Then I set up project-specific virtual directories as children of the "builds" directory, giving me a project URL of the form:

 http://pluralsight.com/builds/Project1/

or

 http://pluralsight.com/builds/Project2/

Note that if you do this, you'll need to modify the web.config file in the project web directories a little bit. Specifically, you'll need to remove the <add> line from the lines that read

 <httpModules>
   <add type="SiteMesh.Filter.SiteMeshModule, SiteMesh" name="SiteMesh" />
 </httpModules>

The reason for this is that when you have nested vdirs like /builds/Project1/, Project1 inherits the web.config settings from builds. And since builds already has the entry for that particular httpModule, listing it again in the web.config for Project1 causes an error.

An alternate strategy for this is to use a flat URL scheme, so that you have URLs that look like this:

 http://pluralsight.com/builds/
 http://pluralsight.com/Project1/
 http://pluralsight.com/Project2/

(Thanks to BradWilson for pointing out this issue.)

You might also be interested in some of the things that Marc Holmes has to say about CruiseControl over at http://bitarray.co.uk/marc/${0}

Below is a notional ccnet.config file that uses this hierarchy to implement multiple projects. Note the similarities between the projects: this makes it easy for me to add additional projects, while still allowing me to customize what files are merged, what web URLs I use, and even what version of NAnt I use to build the projects.

  <cruisecontrol>
    <project name="Project1">
      <state type="state" filename="Project1\ccnet.state" />
      <webURL>http://pluralsight.com/builds/project1</webURL>
      <schedule type="schedule" sleepSeconds="60"/>
      <sourcecontrol type="cvs">
        <executable>cvs.exe</executable>
        <workingDirectory>project1\build</workingDirectory>
        <autoGetSource>false</autoGetSource>
      </sourcecontrol>
      <build type="nant">
        <executable>project1\build\tools\nant-0.84\bin\nant.exe</executable>
        <baseDirectory>project1</baseDirectory>
        <buildArgs>/D:configuration=Release</buildArgs>
        <buildFile>ccnet.build</buildFile>
        <targetList>
        </targetList>
        <buildTimeoutSeconds>300</buildTimeoutSeconds>
      </build>
      <tasks>
        <merge>
          <files>
            <file>project1\build\reports\nunit.xml</file>
            <file>project1\build\reports\version.xml</file>
          </files>
        </merge>
      </tasks>
      <publishers>
        <xmllogger>
          <logDir>project1\web\logs</logDir>
        </xmllogger>
        <email from="builds@pluralsight.com" mailhost="pluralsight.com" includeDetails="TRUE">
          <projectUrl>http://pluralsight.com/builds/project1</projectUrl>
          <users>
            <user name="buildlist" group="always" address="project1-builds@pluralsight.com"/>
          </users>
          <groups>
            <group name="always" notification="always"/>
          </groups>
        </email>
      </publishers>
      <modificationDelaySeconds>10</modificationDelaySeconds>
    </project>


    <project name="Project2">
      <state type="state" filename="Project2\ccnet.state" />
      <webURL>http://pluralsight.com/builds/project2</webURL>
      <schedule type="schedule" sleepSeconds="60"/>
      <sourcecontrol type="cvs">
        <executable>cvs.exe</executable>
        <workingDirectory>project2\build</workingDirectory>
        <autoGetSource>false</autoGetSource>
      </sourcecontrol>
      <build type="nant">
        <executable>project2\build\tools\nant-0.85\bin\nant.exe</executable>
        <baseDirectory>project1</baseDirectory>
        <buildArgs>/D:configuration=Release</buildArgs>
        <buildFile>ccnet.build</buildFile>
        <targetList>
        </targetList>
        <buildTimeoutSeconds>300</buildTimeoutSeconds>
      </build>
      <tasks>
        <merge>
          <files>
            <file>project2\build\reports\fxcop.xml</file>
            <file>project2\build\reports\version.xml</file>
          </files>
        </merge>
      </tasks>
      <publishers>
        <xmllogger>
          <logDir>project2\web\logs</logDir>
        </xmllogger>
        <email from="builds@pluralsight.com" mailhost="pluralsight.com" includeDetails="TRUE">
          <projectUrl>http://pluralsight.com/builds/project2</projectUrl>
          <users>
            <user name="buildlist" group="always" address="project2-builds@pluralsight.com"/>
          </users>
          <groups>
            <group name="always" notification="always"/>
          </groups>
        </email>
      </publishers>
      <modificationDelaySeconds>10</modificationDelaySeconds>
    </project>


  </cruisecontrol>
Nearby
This is CraigAndera's wiki. Visit the HomePage for more info. If you have any feedback, please contact Craig .

About FlexWiki.

Recent Topics