Setting up a Continuous Integration System, Part 9: Conclusion

Setting up and maintaining—not to mention blogging about—a CI environment is a lot of work. It takes time, persistence, and a bit of dedication. Hopefully this series will give you a head start or at least a place to get more information on setting up a new CI environment or maintaining or even improving an existing one.

So, what’s next?

Let’s face it: no development project is ever truly done. The same goes for your CI environment. There’s always a new process, tool, or procedure to add to make it just a little (or maybe a whole lot) better. I hear a lot of good things about NAnt. It’s something I’d like to look into. Ditto for MSBuild scripting, which some people use to perform all of their CI tasks.

On the plug-in front, an immediate improvement to my updver (update version) plug-in would be if the plug-in accepted an array of assembly files to update rather than just the one per task declaration. The end result would be a cleaner and more readable ccnet.config file.

I’m sure there are other things. Perhaps some of them are future blog posts waiting to happen.

That’s it… for now

This concludes this series of posts. I’ll no doubt continue to edit the series as needed, keeping it updated with new ideas and that sort of thing. One of the charters of this blog is to serve as a documentation base for yours truly, so I know I’ll be visiting the posts occasionally for refreshers and just to figure out how or why I did something the way I did it.

Setting up a Continuous Integration System, Part 8: Configuring CruiseControl.NET

September 21, 2009 08:18

This is the next part in an ongoing series about setting up a continuous integration system. The series includes:

  1. Part 1: Introduction
  2. Part 2: Project Folders
  3. Part 3: CI Workflow
  4. Part 4: CI Server Baseline Software
  5. Part 5: CruiseControl.NET Custom Plug-in: Update Version
  6. Part 6: CruiseControl.NET Custom Plug-in: Source Retrieval
  7. Part 7: Installing CruiseControl.NET and Custom Plug-ins
  8. Part 8: Configuring CruiseControl.NET (this post)
  9. Part 9: Conclusion

We’re almost done. By this time you’ve got everything in place to embrace continuous integration. Everything but perhaps the most important part: the configuration of the CI server. Since I use CruiseControl.NET, I’ll next focus on the heart of that configuration, the ccnet.config file.

Resources for Configuring Your CruiseControl.NET Server

Before I jump into the configuration of the config file, let me point out some resources for getting more information. First, there’s ThoughtWorks’ Configuring the Server online help. More specifically, there’s the section on configuring the config file itself, which starts with the CruiseControl Configuration Block. From there, you can drill down into the information for each of the sub-blocks that live beneath <cruisecontrol>.

The Tree View perspective is another nice way of seeing the hierarchy of the ccnet.config file:

image

Editing the ccnet.config file

A quick word on editing the ccnet.config file: It’s just a text file, of course, but it helps to use something other than a plain text editor (like notepad) to edit the file. Any editor with syntax highlighting is going to make the process a lot easier. I use Visual Studio or, more often, Notepad2.

The barebones ccnet.config file

The ccnet.config file lives in C:Program FilesCruiseControl.NETserver. As installed, it’s pretty barren:

   1: <cruisecontrol xmlns:cb="urn:ccnet.config.builder">
   2:     <!-- This is your CruiseControl.NET Server Configuration file. Add your projects below! -->
   3:     <!--
   4:         <project name="MyFirstProject" />
   5:     -->
   6: </cruisecontrol>
View Plain

Not much happening there… yet. Let’s add to the file step-by-step until we have a project that CruiseControl.NET can run through the entire CI process.

I’ll show the full config file as I add each section to keep things in context.

1. Add a Project Configuration Block

The root tag pair is always <cruisecontrol>…</cruisecontrol>. From there, you add one or more <project>’s. I’ll use my Silverlight TagCloud project as an example. Adding the <project> tag with accompanying attributes yields:

   1: <cruisecontrol>
   2:  
   3:     <!-- begin SilverlightTagCloud -->
   4:     <!-- online help: http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block -->
   5:     <project name="SilverlightTagCloud" queue="SilverlightTagCloud" queuePriority="1">
   6:         <workingDirectory>C:devsolutionsSilverlightTagCloud</workingDirectory>
   7:         <artifactDirectory>C:devsolutionsSilverlightTagCloudbinccnetartifacts</artifactDirectory>
   8:         <webURL>http://server_name_or_ip/ccnet/server/local/project/SilverlightTagCloud/ViewLatestBuildReport.aspx</webURL>
   9:         <modificationDelaySeconds>20</modificationDelaySeconds>
  10:     </project>
  11:     <!-- end SilverlightTagCloud -->
  12:  
  13: </cruisecontrol>
View Plain

I don’t use every attribute possible (see the online documentation for a complete list), but I’ll go over the ones I do use.

The <project> attributes I use are:

  • name: The name of the project. This is how it will appear through the CC.NET web interface as well as the cctray client app.
  • queue: CC.NET has this concept of integration queues, where by default each project will run in it’s own queue (or thread). Alternatively, you could run, say, debug and release builds one after the other by labeling them with the same queue name. Now, technically I don’t need this attribute defined, but I did when I used to have separate projects defined for each of debug and release builds. I leave it here now just in case I ever go back to that model.
  • queuePriority: This tells CC.NET the order in which to work on the projects in a queue. ‘1’ indicates highest priority, with ‘0’ denoting the project that will be worked on last after all others have been processed for that queue.
  • workingDirectory: The project’s working folder. I always use absolute paths to avoid confusion.
  • artifactDirectory: The project’s artifact folder where CC.NET task output is stored. Make sure this location is unique per project, otherwise things like NUnit, NCover, etc. sort of output will become mixed up. Again, I use absolute paths to keep things clear.
  • webUrl: The server where CC.NET runs. This is used by the cctray app so that when you double-click a project the web interface is brought up. If you’re hosting on a web server accessible from the Internet you can check the status of your builds from anywhere.
  • modificationDelaySeconds: The minimum amount of seconds to wait after the last check-in is performed. For example, if the modification delay is set to 10 seconds and the last check-in was 7 seconds ago, the system will sleep for 3 seconds before doing anything.

2. Add a Trigger Block

   1: <cruisecontrol>
   2:  
   3:     <!-- begin SilverlightTagCloud -->
   4:     <!-- online help: http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block -->
   5:     <project name="SilverlightTagCloud" queue="SilverlightTagCloud" queuePriority="1">
   6:         <workingDirectory>C:devsolutionsSilverlightTagCloud</workingDirectory>
   7:         <artifactDirectory>C:devsolutionsSilverlightTagCloudbinccnetartifacts</artifactDirectory>
   8:         <webURL>http://server_name_or_ip/ccnet/server/local/project/SilverlightTagCloud/ViewLatestBuildReport.aspx</webURL>
   9:         <modificationDelaySeconds>20</modificationDelaySeconds>
  10:         
  11:         <triggers>
  12:             <!-- triggers help: http://confluence.public.thoughtworks.org/display/CCNET/Interval+Trigger -->
  13:             <intervalTrigger name="continuous" seconds="300" buildCondition="IfModificationExists" />
  14:         </triggers>
  15:  
  16:     </project>
  17:     <!-- end SilverlightTagCloud -->
  18:  
  19: </cruisecontrol>
View Plain

Triggers tell CC.NET when to fire up a new CI cycle. While there are numerous types, I tend to go with the Interval Trigger, which sets a time interval for CC.NET to wake up and do it’s thing. It’s a one line declaration, stuck between the <triggers>…</triggers> tags and, in the above example, uses the following attributes:

  • name: The name of the trigger.
  • seconds: The number of seconds to sleep between integration cycles. I tend to keep this high for my home CC.NET server because I’m not that concerned with having to wait a little while for a build to kick off. At work, I tend to keep this number at 60 seconds.
  • buildCondition: The condition used to determine when to kick off a CI cycle. The value ‘IfModificationExists’ indicates that a build will occur only when source modifications are detected. Our <sourcecontrol> block takes care of the actual determination.

3. Add a State Manager Block

   1: <cruisecontrol>
   2:  
   3:     <!-- begin SilverlightTagCloud -->
   4:     <!-- online help: http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block -->
   5:     <project name="SilverlightTagCloud" queue="SilverlightTagCloud" queuePriority="1">
   6:         <workingDirectory>C:devsolutionsSilverlightTagCloud</workingDirectory>
   7:         <artifactDirectory>C:devsolutionsSilverlightTagCloudbinccnetartifacts</artifactDirectory>
   8:         <webURL>http://server_name_or_ip/ccnet/server/local/project/SilverlightTagCloud/ViewLatestBuildReport.aspx</webURL>
   9:         <modificationDelaySeconds>20</modificationDelaySeconds>
  10:         
  11:         <triggers>
  12:             <!-- triggers help: http://confluence.public.thoughtworks.org/display/CCNET/Interval+Trigger -->
  13:             <intervalTrigger name="continuous" seconds="300" buildCondition="IfModificationExists" />
  14:         </triggers>
  15:  
  16:         <state type="state" directory="C:ccnetstate" />
  17:         
  18:     </project>
  19:     <!-- end SilverlightTagCloud -->
  20:  
  21: </cruisecontrol>
View Plain

The State Manager Block tells CC.NET where to store such information as the build label, the time of the build, the outcome of the build, etc. It’s a pretty simple block. I use the same location for all projects. It doesn’t seem to cause any issues.

4. Add a Source Control Block

   1: <cruisecontrol>
   2:  
   3:     <!-- begin SilverlightTagCloud -->
   4:     <!-- online help: http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block -->
   5:     <project name="SilverlightTagCloud" queue="SilverlightTagCloud" queuePriority="1">
   6:         <workingDirectory>C:devsolutionsSilverlightTagCloud</workingDirectory>
   7:         <artifactDirectory>C:devsolutionsSilverlightTagCloudbinccnetartifacts</artifactDirectory>
   8:         <webURL>http://server_name_or_ip/ccnet/server/local/project/SilverlightTagCloud/ViewLatestBuildReport.aspx</webURL>
   9:         <modificationDelaySeconds>20</modificationDelaySeconds>
  10:         
  11:         <triggers>
  12:             <!-- triggers help: http://confluence.public.thoughtworks.org/display/CCNET/Interval+Trigger -->
  13:             <intervalTrigger name="continuous" seconds="300" buildCondition="IfModificationExists" />
  14:         </triggers>
  15:  
  16:         <state type="state" directory="C:ccnetstate" />
  17:         
  18:         <sourcecontrol type="svnget">
  19:             <executable>c:program filesVisualSVNbinsvn.exe</executable>
  20:             <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  21:         </sourcecontrol>
  22:         
  23:     </project>
  24:     <!-- end SilverlightTagCloud -->
  25:  
  26: </cruisecontrol>
View Plain

The Source Control Block defines from where CC.NET should pull source. My experience up to this point involves use of the blocks for Visual SourceSafe, Subversion, and Team Foundation Server. They all function more or less the same; source control is source control, from the perspective of CC.NET, anyway. In a previous post in this series I discussed my own custom source control plug-in for Subversion. I also explained why I use my own as opposed to using the stock one, so I won’t go into that now. You should note that using one or the other is really not that dissimilar.

Briefly, the source control block’s attributes:

  • type: The source control product to use.
  • executable: The location of the svn executable.
  • workingDirectory: The local project folder.

5. Add a Labeller Block

   1: <cruisecontrol>
   2:  
   3:     <!-- begin SilverlightTagCloud -->
   4:     <!-- online help: http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block -->
   5:     <project name="SilverlightTagCloud" queue="SilverlightTagCloud" queuePriority="1">
   6:         <workingDirectory>C:devsolutionsSilverlightTagCloud</workingDirectory>
   7:         <artifactDirectory>C:devsolutionsSilverlightTagCloudbinccnetartifacts</artifactDirectory>
   8:         <webURL>http://server_name_or_ip/ccnet/server/local/project/SilverlightTagCloud/ViewLatestBuildReport.aspx</webURL>
   9:         <modificationDelaySeconds>20</modificationDelaySeconds>
  10:         
  11:         <triggers>
  12:             <!-- triggers help: http://confluence.public.thoughtworks.org/display/CCNET/Interval+Trigger -->
  13:             <intervalTrigger name="continuous" seconds="300" buildCondition="IfModificationExists" />
  14:         </triggers>
  15:  
  16:         <state type="state" directory="C:ccnetstate" />
  17:         
  18:         <sourcecontrol type="svnget">
  19:             <executable>c:program filesVisualSVNbinsvn.exe</executable>
  20:             <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  21:         </sourcecontrol>
  22:         
  23:         <labeller type="iterationlabeller">
  24:             <prefix>1.0</prefix>
  25:             <duration>1</duration>
  26:             <releaseStartDate>2009/8/15</releaseStartDate>
  27:             <separator>.</separator>
  28:         </labeller>
  29:         
  30:     </project>
  31:     <!-- end SilverlightTagCloud -->
  32:  
  33: </cruisecontrol>
View Plain

The Labeller Block is used by CC.NET to generate build version labels. This label can then be used to version your assemblies. I like the Iteration Labeller, which takes the following attributes:

  • prefix: Any string to prepend to a label.
  • duration: The duration of the iteration in weeks; helps define how the label will be incremented.
  • releaseStartDate: The start date for iteration one. I typically use the date in which I added the project to CC.NET, just to start things off somewhere.
  • separator: The separator between iteration number and build number.

6. Add a Prebuild Block

   1: <cruisecontrol>
   2:  
   3:     <!-- begin SilverlightTagCloud -->
   4:     <!-- online help: http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block -->
   5:     <project name="SilverlightTagCloud" queue="SilverlightTagCloud" queuePriority="1">
   6:         <workingDirectory>C:devsolutionsSilverlightTagCloud</workingDirectory>
   7:         <artifactDirectory>C:devsolutionsSilverlightTagCloudbinccnetartifacts</artifactDirectory>
   8:         <webURL>http://server_name_or_ip/ccnet/server/local/project/SilverlightTagCloud/ViewLatestBuildReport.aspx</webURL>
   9:         <modificationDelaySeconds>20</modificationDelaySeconds>
  10:         
  11:         <triggers>
  12:             <!-- triggers help: http://confluence.public.thoughtworks.org/display/CCNET/Interval+Trigger -->
  13:             <intervalTrigger name="continuous" seconds="300" buildCondition="IfModificationExists" />
  14:         </triggers>
  15:  
  16:         <state type="state" directory="C:ccnetstate" />
  17:         
  18:         <sourcecontrol type="svnget">
  19:             <executable>c:program filesVisualSVNbinsvn.exe</executable>
  20:             <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  21:         </sourcecontrol>
  22:         
  23:         <labeller type="iterationlabeller">
  24:             <prefix>1.0</prefix>
  25:             <duration>1</duration>
  26:             <releaseStartDate>2009/8/15</releaseStartDate>
  27:             <separator>.</separator>
  28:         </labeller>
  29:         
  30:         <prebuild>
  31:             <!-- assembly version update prior to build -->
  32:             <svnupdver>
  33:                <executable>c:program filesVisualSVNbinsvn.exe</executable>
  34:                <assemblyInfoFolder>C:devsolutionsSilverlightTagCloudprojectsTagCloudControlProperties</assemblyInfoFolder>
  35:             </svnupdver>
  36:            <svnupdver>
  37:               <executable>c:program filesVisualSVNbinsvn.exe</executable>
  38:               <assemblyInfoFolder>C:devsolutionsSilverlightTagCloudprojectsTagCloudServiceProperties</assemblyInfoFolder>
  39:            </svnupdver>
  40:         </prebuild>
  41:         
  42:     </project>
  43:     <!-- end SilverlightTagCloud -->
  44:  
  45: </cruisecontrol>
View Plain

The Prebuild Block is a container for Task Blocks. I typically perform my assembly version update here via my own custom plug-in, though you can just as easily do it in the main Tasks Block.

7. Add a Task Block

   1: <cruisecontrol>
   2:  
   3:     <!-- begin SilverlightTagCloud -->
   4:     <!-- online help: http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block -->
   5:     <project name="SilverlightTagCloud" queue="SilverlightTagCloud" queuePriority="1">
   6:         <workingDirectory>C:devsolutionsSilverlightTagCloud</workingDirectory>
   7:         <artifactDirectory>C:devsolutionsSilverlightTagCloudbinccnetartifacts</artifactDirectory>
   8:         <webURL>http://server_name_or_ip/ccnet/server/local/project/SilverlightTagCloud/ViewLatestBuildReport.aspx</webURL>
   9:         <modificationDelaySeconds>20</modificationDelaySeconds>
  10:         
  11:         <triggers>
  12:             <!-- triggers help: http://confluence.public.thoughtworks.org/display/CCNET/Interval+Trigger -->
  13:             <intervalTrigger name="continuous" seconds="300" buildCondition="IfModificationExists" />
  14:         </triggers>
  15:  
  16:         <state type="state" directory="C:ccnetstate" />
  17:         
  18:         <sourcecontrol type="svnget">
  19:             <executable>c:program filesVisualSVNbinsvn.exe</executable>
  20:             <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  21:         </sourcecontrol>
  22:         
  23:         <labeller type="iterationlabeller">
  24:             <prefix>1.0</prefix>
  25:             <duration>1</duration>
  26:             <releaseStartDate>2009/8/15</releaseStartDate>
  27:             <separator>.</separator>
  28:         </labeller>
  29:         
  30:         <prebuild>
  31:            <!-- assembly version update prior to build -->
  32:            <svnupdver>
  33:               <executable>c:program filesVisualSVNbinsvn.exe</executable>
  34:               <assemblyInfoFolder>C:devsolutionsSilverlightTagCloudprojectsTagCloudControlProperties</assemblyInfoFolder>
  35:           </svnupdver>
  36:           <svnupdver>
  37:              <executable>c:program filesVisualSVNbinsvn.exe</executable>
  38:              <assemblyInfoFolder>C:devsolutionsSilverlightTagCloudprojectsTagCloudServiceProperties</assemblyInfoFolder>
  39:           </svnupdver>
  40:         </prebuild>
  41:         
  42:         <tasks>
  43:             <!-- msbuild task help: http://confluence.public.thoughtworks.org/display/CCNET/MsBuild+Task -->
  44:             <msbuild>
  45:                 <executable>C:WIN2003Microsoft.NETFrameworkv3.5MSBuild.exe</executable>
  46:                 <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  47:                 <projectFile>SilverlightTagCloud.sln</projectFile>
  48:                 <buildArgs>/noconsolelogger /p:Configuration=Debug /v:Minimal</buildArgs>
  49:                 <targets>Build</targets>
  50:                 <timeout>900</timeout>
  51:                 <logger>c:Program FilesCruiseControl.NETserverRodemeyer.MsBuildToCCNet.dll</logger>
  52:             </msbuild>
  53:             <msbuild>
  54:                 <executable>C:WIN2003Microsoft.NETFrameworkv3.5MSBuild.exe</executable>
  55:                 <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  56:                 <projectFile>SilverlightTagCloud.sln</projectFile>
  57:                 <buildArgs>/noconsolelogger /p:Configuration=Release /v:Minimal</buildArgs>
  58:                 <targets>Build</targets>
  59:                 <timeout>900</timeout>
  60:                 <logger>c:Program FilesCruiseControl.NETserverRodemeyer.MsBuildToCCNet.dll</logger>
  61:             </msbuild>
  62:             <exec>
  63:                 <executable>C:devdeployziprelease.bat</executable>
  64:                 <environment>
  65:                     <variable>
  66:                         <name>BUILDNAME</name>
  67:                         <value>SilverlightTagCloud</value>
  68:                     </variable>
  69:                 </environment>
  70:             </exec>
  71:         </tasks>
  72:         
  73:     </project>
  74:     <!-- end SilverlightTagCloud -->
  75:  
  76: </cruisecontrol>
View Plain

The Task Block is the main workhorse of the CC.NET CI system. It is where you would typically put your build tasks, run unit tests, etc. For the full list of tasks, see the Task Blockdocumentation.

As you can see above, the SilverlightTagCloud project doesn’t have a lot of tasks. It builds Debug, it builds Release, and it zips the release via a batch file within an Exec Task. Other steps I like to add to the tasks section are NCover via an Exec Task (you can alternatively use the NCover Reporting Task) and NUnit Testing via the NUnit Task, but because Silverlight still has limited unit testing tools and, well, I don’t see the point of adding code coverage to something that has limited unit testing to begin with, those sections are not here. In the interest of being thorough, however, I’ll include examples from another project so you can at least see them defined.

First, the MSBuild Tasks’ attributes:

  • executable: The location of the msbuild.exe executable.
  • workingDirectory: The project’s root folder.
  • projectFile: The solution or project file to build.
  • buildArgs: Any arguments to pass to msbuild.
  • targets: A list of targets to run (i.e., Build; Test).
  • timeout: Number of seconds to wait before assuming we’re hung and to time the build out.
  • logger: If you’re using a custom logger, specify that here.

Now, the Exec Task. An Exec Task is a general purpose task wherein you can run just about anything you want. Here, I use it to run a batch file that zips up the project’s source, build output, etc. (using the 7zip command line application). One of the nice features of CC.NET is that it will store things like the build label as an environment variable that you can then use in a batch file. I use the label as part of the zip file’s name, so something like “SilverlightTagCloud v1.0.7.8.zip”. This file, which constitutes a release candidate, is then stored away in a shared build archive folder.

The attributes of the Exec Task that I use are:

  • executable: The program to run.
  • environment: Used to specify environment variables to set for the running executable. Here I set BUILDNAME to “SilverlightTagCloud”, which is used to construct the name of the .zip file.

Now, to throw in how I use NCover and NUnit.

For NCover, you can use the NCover Reporting Task or, as I do, an exec task (see the Using CruiseControl.NET with NCover tutorial for more info; remember to add a merge task):

   1: <exec>
   2:     <executable>"C:Program FilesNCoverNCover.Console.exe"</executable>
   3:     <buildArgs>"C:Program FilesNUnit 2.4.7binnunit-console.exe"
   4:         //w "C:projectsolutionsprojectnamebindebug"
   5:         //x "C:projectsolutionsprojectnamebinccnetartifactsncoverproject-coverage.xml"
   6:         //l "C:projectsolutionsprojectnamebinccnetartifactsncoverproject-coverage.log"
   7:         "C:projectsolutionsprojectnamebinclientdebugprojectname.dll"</buildArgs>
   8: </exec>
View Plain

For NUnit, I use the NUnit Task:

   1: <nunit path="C:Program FilesNUnit 2.4.7binnunit-console.exe">
   2:     <assemblies>
   3:         <assembly>C:projectsolutionsprojectnamebinclientdebugprojectname.dll</assembly>
   4:     </assemblies>
   5: </nunit>
View Plain

8. Add Publishers

I use two publishers: one to log modification information (as in when a code file has changed) and another, the XML Log Publisher, which the CC.NET documentation states, “The Xml Log Publisher is used to create the log files used by the CruiseControl.NET Web Dashboard, so if you don’t define an <xmllogger /> section the Dashboard will not function correctly”. Not much more to say about it beyond that. See the conclusion for usage of the <publishers> task.

Conclusion

Here, then, is the complete ccnet.config file for the SilverlightTagCloud project:

   1: <cruisecontrol>
   2:  
   3:     <!-- begin SilverlightTagCloud -->
   4:     <!-- online help: http://confluence.public.thoughtworks.org/display/CCNET/Project+Configuration+Block -->
   5:     <project name="SilverlightTagCloud" queue="SilverlightTagCloud" queuePriority="1">
   6:         <workingDirectory>C:devsolutionsSilverlightTagCloud</workingDirectory>
   7:         <artifactDirectory>C:devsolutionsSilverlightTagCloudbinccnetartifacts</artifactDirectory>
   8:         <webURL>http://server_name_or_ip/ccnet/server/local/project/SilverlightTagCloud/ViewLatestBuildReport.aspx</webURL>
   9:         <modificationDelaySeconds>20</modificationDelaySeconds>
  10:         
  11:         <triggers>
  12:             <!-- triggers help: http://confluence.public.thoughtworks.org/display/CCNET/Interval+Trigger -->
  13:             <intervalTrigger name="continuous" seconds="300" buildCondition="IfModificationExists" />
  14:         </triggers>
  15:  
  16:         <state type="state" directory="C:ccnetstate" />
  17:         
  18:         <sourcecontrol type="svnget">
  19:             <executable>c:program filesVisualSVNbinsvn.exe</executable>
  20:             <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  21:         </sourcecontrol>
  22:         
  23:         <labeller type="iterationlabeller">
  24:             <prefix>1.0</prefix>
  25:             <duration>1</duration>
  26:             <releaseStartDate>2009/8/15</releaseStartDate>
  27:             <separator>.</separator>
  28:         </labeller>
  29:         
  30:         <prebuild>
  31:            <!-- assembly version update prior to build -->
  32:            <svnupdver>
  33:               <executable>c:program filesVisualSVNbinsvn.exe</executable>
  34:               <assemblyInfoFolder>C:devsolutionsSilverlightTagCloudprojectsTagCloudControlProperties</assemblyInfoFolder>
  35:           </svnupdver>
  36:           <svnupdver>
  37:              <executable>c:program filesVisualSVNbinsvn.exe</executable>
  38:              <assemblyInfoFolder>C:devsolutionsSilverlightTagCloudprojectsTagCloudServiceProperties</assemblyInfoFolder>
  39:           </svnupdver>
  40:         </prebuild>
  41:         
  42:         <tasks>
  43:             <!-- msbuild task help: http://confluence.public.thoughtworks.org/display/CCNET/MsBuild+Task -->
  44:             <msbuild>
  45:                 <executable>C:WIN2003Microsoft.NETFrameworkv3.5MSBuild.exe</executable>
  46:                 <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  47:                 <projectFile>SilverlightTagCloud.sln</projectFile>
  48:                 <buildArgs>/noconsolelogger /p:Configuration=Debug /v:Minimal</buildArgs>
  49:                 <targets>Build</targets>
  50:                 <timeout>900</timeout>
  51:                 <logger>c:Program FilesCruiseControl.NETserverRodemeyer.MsBuildToCCNet.dll</logger>
  52:             </msbuild>
  53:             <msbuild>
  54:                 <executable>C:WIN2003Microsoft.NETFrameworkv3.5MSBuild.exe</executable>
  55:                 <workingDirectory>c:devsolutionsSilverlightTagCloud</workingDirectory>
  56:                 <projectFile>SilverlightTagCloud.sln</projectFile>
  57:                 <buildArgs>/noconsolelogger /p:Configuration=Release /v:Minimal</buildArgs>
  58:                 <targets>Build</targets>
  59:                 <timeout>900</timeout>
  60:                 <logger>c:Program FilesCruiseControl.NETserverRodemeyer.MsBuildToCCNet.dll</logger>
  61:             </msbuild>
  62:             <exec>
  63:                 <executable>C:devdeployziprelease.bat</executable>
  64:                 <environment>
  65:                     <variable>
  66:                         <name>BUILDNAME</name>
  67:                         <value>SilverlightTagCloud</value>
  68:                     </variable>
  69:                 </environment>
  70:             </exec>
  71:         </tasks>
  72:         
  73:         <publishers>
  74:             <!-- modificationHistory help: http://confluence.public.thoughtworks.org/display/CCNET/ModificationHistory+Publisher -->
  75:             <modificationHistory onlyLogWhenChangesFound="true" />
  76:             <xmllogger logDir="buildlogs" />
  77:             <statistics />
  78:         </publishers>
  79:         
  80:     </project>
  81:     <!-- end SilverlightTagCloud -->
  82:  
  83: </cruisecontrol>