Setting Up Continuous Integration

posted on 2004-08-14 at 16:45:43 by Joel Ross

I've set up CruiseControl.Net for three projects now, and each time, I have to try to remember the steps needed to do it, so I figured I would just write them down, and maybe help someone else figure out the process.

First, what is CruiseControl.Net? It's a tool that tracks your project's source code for changes made (i.e, check-ins). When check-ins happen, CruiseControl.Net uses Nant to do a build. The main advantage of this is that every person on the team knows if the build is working or not. If the build is broken, members on the team receive email notifications, as well as notifications when the build is fixed. This is a much easier approach to builds than a once a week build where you don't know from day to day if the code base is in good working form. Plus the build process is automatic, meaning no need for someone to manually run the build on Friday afternoon.

Anyway, setting it up isn't really that hard. There's just a few steps needed. First, you have to download CruiseControl.Net, Nant, and NantContrib. NantContrib has extra tasks (such as source control system integrations) that aren't part of Nant. Optionally, you can also download Nunit (more on that later). Extract the files into a known directory structure. Personally, I like the following directory structure:

/Sourcecontrol
  /BuildProcess
    /CCNet
    /Nant
    /Nunit
  /CurrentCode
    /Project1
    /Project2

Sourcecontrol would be your root, and all of your current code would be in the current code folder. I put the NantContrib dlls directly into the nant/bin folder and haven't had any issues, but there is another way to completely avoid any conflicts that could occur. Personally, I haven't had any issues doing it this way.

Next, install the ccservice by running installutil (located in the Windows/Microsoft.NET/[version]/ folder. Make sure the files are writeable in the folder (/CCNet/Server folder). Edit the ccservice.exe.config file to ensure the ccnet.config key is pointing to the ccnet.config file in the /CCNet/Server folder. You can also move this file elsewhere if you want. Also, if you want to use the cctray service, which allows a tray icon to tell you the current build status, then turn remoting on. Once that is done, the service can be started. You'll also probably want to change the startup type to be automatic, so it runs when windows starts, rather then having to manually start the service after every reboot.

Once the service is ready to go, we need to configure the ccnet.config file to define our projects. For now, I'll describe the process for one project, then afterwards, highlight what needs to change for multiple projects.

Here's an example config file:

<cruisecontrol>
  <project name="[Project Name]">
    <webURL>http://www.mydomain.com/ccnet</webURL>
    <schedule type="schedule" sleepSeconds="60"/>
    <modificationDelaySeconds>10</modificationDelaySeconds>
    <sourcecontrol type="vault">
      <executable>c:\program files\sourcegear\vault client\vault.exe</executable>
      <username>[BuildUser]</username>
      <password>[Password]</password>
      <host>www.mydomain.com</host>
      <repository>[Repository]</repository>
      <folder>$/CurrentCode</folder>
      <ssl>False</ssl>
    </sourcecontrol>
    <build type="nant">
      <executable>c:\sourcesafe\BuildProcess\NAnt\bin\nant.exe</executable>
      <baseDirectory>c:\sourcesafe\CurrentCode\</baseDirectory>
      <buildFile>C:\Sourcesafe\CurrentCode\cruise.build</buildFile>
      <buildTimeoutSeconds>300</buildTimeoutSeconds>
    </build>
    <publishers>
      <xmllogger>
        <logDir>..\website\log</logDir>
      </xmllogger>
      <email from="buildmaster@mydomain.com" mailhost="[Mail]" includeDetails="TRUE">
        <projectUrl>http://www.mydomain.com/CCNet</projectUrl>
        <users>
          <user name="[name1]" group="buildmaster" address="name1@mydomain.com"/>
          <user name="[name2" group="developers" address="name2@mydomain.com"/>
        </users>
        <groups>
          <group name="developers" notification="change"/>
          <group name="buildmaster" notification="always"/>
        </groups>
      </email>
    </publishers>
  </project>
</cruisecontrol>

Here's the highlights. The webURL is the IIS mapped site to the /CCNet/Web folder, which is where you'll go to see the history of the builds. We'll talk about setting that up in a bit.

This file is set up for Vault source control, which is a very solid source control system. I've been very pleased with it. I've also set it up against Visual Sourcesafe, and that works very well too. If you do it against VSS, up the modificationDelaySeconds, as the check ins are not atomic. They are with Vault. Anyway, you set up a folder in the source control system to monitor. In this case, it's the CurrentCode folder.

To see how to set up the system for other source control systems, and which ones are supported, see the CruiseControl.NET website.

The build type is Nant, meaning it will use Nant to process your builds. You set up the base directory, and which build file to kick off.

The last major section is the email section. You set up who it's from and how to send it, and then which users get email and when. A notification of change will notify the users whenever the build status changes, and always will, well, always send emails when a build takes place.

Let's talk website now. The CCNet/Web folder is the website that tracks everything. Set up a sub folder in IIS pointing to the /CCNet/Website/Log folder, and then edit the web.config in the /CCNet/Web folder. Make sure the logDir value is log, and the serverLogFilePath points to /CCNet/Website/Log. That's it for the website.

Almost done now. The next part is the Nant build files, which do the building of the project. For simplicity, we'll use the solution task to build the solution. You can also use the csc task to build the files, but it is a little more involved, and there's debate as to whether it's a better way to do it or not. Personally, I think the solution task is good enough for most needs, and the custom csc task is useful when you need more control over how the files are built.

Anyway, here's a sample build file (cruise.build)

<project name="[Project Name]" default="go">
  <target name="go" depends="Update,Build" />
  <target name="Update">
    <exec basedir="." program="c:\program files\sourcegear\vault client\vault.exe" commandline="GET $/CurrentCode -host www.mydomain.com: -username [BuildUser] -password [password] -repository [Repository] -destpath C:\Sourcesafe\CurrentCode\"/>
  </target>
  <target name="Build" depends="Update">
    <nant buildfile="project.build" target="Debug" inheritall="true" />
  </target>
</project>

I won't go into the details of how Nant works, but this basically says the default target is "go", and go depends on Update and Build. The update task retrieves the latest version from Vault, and the Build target uses a sub-nant file to do the build.

Now, the sub-nant file, and we're done!

<project name="NCM.PLC.Website" default="Debug">
  <target name="Debug">
    <solution configuration="Debug" solutionfile="[MySolution].sln">
      <webmap>
        <map url="http://localhost/[MySite]/[MySite].csproj" path="c:\inetpub\wwwroot\[MySite]\[MySite].csproj" />
      </webmap>
    </solution>
  </target>
</project>

This tells nant to do a build based on the solution file. The webmap is used for any websites in the project.

Once that's done, check in a file in the /CurrentCode folder. The build should fire automatically.

That's it. Go forth, and integrate continuously!

Or, if you're still reading, here's some more information. Tip: Get the project loading in VS.NET on the build server. Once you do that, the build process will be much easier.

If the build process isn't behaving, run the cruise.build file manually and see where the process is dying.

The /CCNet/cctray folder contains the tray application. Fire it up, and change the settings. Set the server to be tcp://www.mydomian.com:21234/CruiseManager.rem. The port 21234 is the default port. You can change this if you'd like. Once you enter that, it should connect to your build server, and you'll see the build status.

And we can't forget unit testing! Optionally, you can use the Nunit2 task to run any unit tests you have also. Here's a sample task for it. Just add this to a target that gets run during the process.

<nunit2>
  <formatter type="Xml" usefile="false" />
  <test assemblyname="[MyTests]\bin\Debug\[MyTests].dll" appconfig="[MyTests]\[MyTests].dll.config" />
</nunit2>

Just add the unit test DLL to your solution, and it will get included in this.

Maybe some day, I'll go more in-depth into the Nant build file, but for now, this should be enough to get started.

Categories: ASP.NET