Setting up CruiseControl.NET with MSBuild#

Just setup CruiseControl.NET (CC.NET) on a fresh install of Windows 2003 server. It went pretty seamless.

For now, we are only doing continuous integration, but very soon we are going to set it up for NUnit and FxCop too. If you plan on using it, here are the steps I followed. Note that we are using Subversion for our source control and that the box had nothing on it.

1. Download and install Subversion (http://subversion.tigris.org/project_packages.html).
2. Create a working directory and get latest from trunk.
3. Download CC.NET (http://confluence.public.thoughtworks.org/display/CCNET/Welcome+to+CruiseControl.NET).
4. Download CC.NET Tray (http://confluence.public.thoughtworks.org/display/CCNET/CCTray).
5. Install CC.NET.
6. Modify CC.NET Server configuration file to monitor your source control working directory and to call MSBuild.
7. Modify CC.NET web dashboard configuration file to show MSBuild output.

CC.NET can provide build updates via email notification or to a utility that you can install on your desktop (CCTray). We decided to go this route rather than have CC.NET email us. The cool thing about the tray utility is that it sits in your system tray and the icon will change when a build starts and the result of the build.

If you have never used CC.NET or the Java version, note that CC.NET has a server application that can be run as an NT Service (named CruiseControl.NET Server). You can configure the service to start automatically via the service control MMC. CC.NET also has a web dashboard that is used to view build outputs. The dashboard application gets installed under Program Files\CruiseControl.NET\webdashboard\.  If you use configure CC.NET to call MSBuild, then you'll want to also add an entry to the dashboard.config file to include a link to the MSBuild output.

Most of the setup of CC.NET was easy, the only problem I had was that I working off of an old configuration file and that one was not configured for MSBuild. Here is the server configuration file (ccnet.config), followed by the dashboard config file.

<!-- ************************************************* -->
<cruisecontrol>
 <project name="YourAppName">
  <!-- after a change is detected, wait 10 mins and then kick off the build-->
  <schedule type="schedule" sleepSeconds="600" />
  <!--set the sourcecontrol type to subversion and point to the subversion exe-->
  <sourcecontrol type="svn">
   <executable>C:\Program Files\Subversion\bin\svn.exe</executable>
   <workingDirectory>D:\CruiseControl\yourapp\build\checkout</workingDirectory>
   <trunkUrl>svn://servername/Projects/yourapp/trunk/Source</trunkUrl>
   <autoGetSource>true</autoGetSource>
   <username>sayed</username>
   <password>password</password>
  </sourcecontrol>
  <tasks>
   <!-- Configure MSBuild to compile the updated files -->
   <msbuild>
    <executable>C:\WINNT\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe</executable>
    <workingDirectory>D:\CruiseControl\YOURAPP\build\checkout\Solutions\YourSolution</workingDirectory>
    <projectFile>YourSolutionFileName.sln</projectFile>
    <buildArgs>/noconsolelogger /p:Configuration=Debug</buildArgs>
    <targets></targets>
    <timeout>15</timeout>
    <logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,ThoughtWorks.CruiseControl.MsBuild.dll</logger>
   </msbuild>
  </tasks>
  <!--Publishers will be done after the build has completed-->
  <publishers>
   <xmllogger>
    <logDir>d:\cruisecontrol\yourapp\logs</logDir>
   </xmllogger>
   <email from="alerts@sayedhashimi.com" mailhost="yoursmtp.yourcompany.com" includeDetails="TRUE">
    <projectUrl>http://yourservername/ccnet</projectUrl>
    <users>
     <user name="Sayed" group="developers" address="sayed@sayedhashimi.com"/>
    </users>
    <groups>
     <group name="developers" notification="always">
    </groups>
   </email>
  </publishers>
  <modificationDelaySeconds>10</modificationDelaySeconds>
 </project>

</cruisecontrol>
<!-- ************************************************* -->

Here is the dashboard.config file I am using:

<!-- ************************************************* -->
<?xml version="1.0" encoding="utf-8" ?>
<dashboard>
 <remoteServices>
  <servers>
   <!-- Update this list to include all the servers you want to connect to. NB - each server name must be unique -->
   <server name="local" url="tcp://localhost:21234/CruiseManager.rem" />
  </servers>
 </remoteServices>
 <plugins>
  <farmPlugins>
   <farmReportFarmPlugin />
   <cctrayDownloadPlugin />
  </farmPlugins>
  <serverPlugins>
   <serverReportServerPlugin />
   <serverLogServerPlugin />
   <serverInformationServerPlugin />
  </serverPlugins>
  <projectPlugins>
   <projectReportProjectPlugin />
   <latestBuildReportProjectPlugin />
   <viewAllBuildsProjectPlugin />
  </projectPlugins>
  <buildPlugins>
   <buildReportBuildPlugin>
    <xslFileNames>
     <xslFile>xsl\header.xsl</xslFile>
     <xslFile>xsl\modifications.xsl</xslFile>
     <xslFile>xsl\compile.xsl</xslFile>
     <xslFile>xsl\unittests.xsl</xslFile>
     <xslFile>xsl\MsTestSummary.xsl</xslFile>
     <xslFile>xsl\fxcop-summary.xsl</xslFile>
     <xslFile>xsl\NCoverSummary.xsl</xslFile>
     <xslFile>xsl\SimianSummary.xsl</xslFile>
    </xslFileNames>
   </buildReportBuildPlugin>
   <buildLogBuildPlugin />
   <xslReportBuildPlugin description="MSBuild Output" actionName="MSBuildOutputBuildPlugin" xslFileName="xsl\msbuild.xsl" />
   <xslReportBuildPlugin description="NUnit Details" actionName="NUnitDetailsBuildReport" xslFileName="xsl\tests.xsl" />
   <xslReportBuildPlugin description="NUnit Timings" actionName="NUnitTimingsBuildReport" xslFileName="xsl\timing.xsl" />
   <xslReportBuildPlugin description="FxCop Report" actionName="FxCopBuildReport" xslFileName="xsl\FxCopReport.xsl" />
   <!--
   <xslReportBuildPlugin description="NAnt Output" actionName="NAntOutputBuildReport" xslFileName="xsl\Nant.xsl" />
   <xslReportBuildPlugin description="NAnt Timings" actionName="NAntTimingsBuildReport" xslFileName="xsl\NantTiming.xsl" />
   <xslReportBuildPlugin description="NCover Report" actionName="NCoverBuildReport" xslFileName="xsl\NCover.xsl" />
   <xslReportBuildPlugin description="Simian Report" actionName="SimianBuildReport" xslFileName="xsl\SimianReport.xsl"/>
   -->
   <!-- This is an example of using Project-specific build plugins
   <xslReportBuildPlugin description="My Report" actionName="MyReport" xslFileName="xsl\MyReport.xsl">
    <includedProjects>
     <projectName>My Project</projectName>
    </includedProjects>
   </xslReportBuildPlugin>
   <xslReportBuildPlugin description="My Other Report" actionName="MyOtherReport" xslFileName="xsl\MyOtherReport.xsl">
    <excludedProjects>
     <projectName>My Project</projectName>
    </excludedProjects>
   </xslReportBuildPlugin>
   -->
  </buildPlugins>
 </plugins>
</dashboard>
<!-- ************************************************* -->

2/8/2006 11:46:22 AM (Eastern Standard Time, UTC-05:00) #    Comments [3]  |  Trackback

 

ClickOnce Updates of Data Files#

In my previous post, I talked about how ClickOnce udpates applications but forgot to mention something specific to data files. ClickOnce deployed applications might use files that need to be migrated from one version to another. For example, an access database. ClickOnce supports this but with respect to downloading updates, data files are always downloaded (and need to be synchronized with the version on the client). ClickOnce doesn't even look at the hash when it sees that a file is marked as a data file.

2/8/2006 8:33:01 AM (Eastern Standard Time, UTC-05:00) #    Comments [3]  |  Trackback

 

ClickOnce Application Management#

I was recently asked a question concerning how the publisher of a ClickOnce application can force removal of an assembly after an update. Here is the question:

 

Questions: If my application no longer needs an assembly, does ClickOnce ensure that the file is deleted when I do an update?

 

Answer: ClickOnce installs applications within the %userprofile% folder. At any time, ClickOnce will have up to two versions of an application for a given user. When ClickOnce has to do an update, it's smart enough to only download files that have changed, and not copy files that have been deleted. ClickOnce does updates using the files listed in the application manifest file, on the server, and the files that are in the existing application folder. So image for a second that we have an application with three files: an exe (myapp.exe), a supporting assembly (mysupport.dll) and another supporting assembly named "anothersupport.dll". Lets now assume that we have deployed version 1.0 to our clients.

 

After deploying version 1.0, we decide that mysupport.dll is no longer needed because there is a major security flaw in it. In fact, we decide to purchase the same functionality from a 3rd party that doesn't have any security issues. What happens when we do an update? Does the assembly with the security flaw stay on the user's machine?

 

The answer is yes, but only until you do another update. We said earlier that ClickOnce maintain up to two version of an application for a given user. When you update your application, ClickOnce looks at the files you have listed in the application manifest and the files in the existing application folder on the client, to decide what to download and what not to download. ClickOnce does this to ensure that it doesn't download a file that was not modified. When ClickOnce sees that a file entry exists in the application manifest and does not exist in the existing application directory on the client, it knows that the file was added to the application and so it downloads the file. If it sees that a file is in the application manifest and is also in the existing application directory and the files have the same hash, then it just copies the file from the existing application directory to the new application directory. If a file exists in the application directory that is not in the application manifest, then ClickOnce leaves that file in the existing application directory. The reason it leaves the file is for rollback purposes. ClickOnce, supports "rollback to previous version" so it keeps the existing application just in case the user decides to go back to the old application. Can you get rid of the file manually? Technically you could, but the ClickOnce app store is not meant to be tampered with--ClickOnce manages the app store.

2/7/2006 8:17:41 AM (Eastern Standard Time, UTC-05:00) #    Comments [3]  |  Trackback

 

Working towards an automated ClickOnce Deployment#

If you have an automated build process around a ClickOnce deployment, you should know how ClickOnce determines updates to files. Why is this important? Well, lets say that you are using MSBuild to do scheduled builds every day (say 3 times a day). Your build process starts out by getting the lastest code from your source control system and then builds all the projects and assemblies of your application. It then creates the application and deployment manifest (the ClickOnce manifest files) and then pushes updates to the deployment server.

The potential problem with this approach is that if your build process rebuilds all of the assemblies used by your application, even if they were not modified, then ClickOnce will think the file has changed and will have to download the entire application again--just as if it were the initial install. This is an obvious problem and it has to do with how ClickOnce calculates a change to a file.

ClickOnce is driven by two manifest files: the application manifest and the deployment manifest. The application manifest has details about a particular version of an application. For example, the dependent assemblies of a particular version of an application. The deployment manifest has details about the application as a whole and not specific details about a particular version. The deployment manifest, for example, will have the update policy of the application.

Going back to our problem. I said that the application manifest has details about the files that comprise a specific version of an application. For example, if an application depends on an assembly called "MyCoolAssembly", then the application manifest will have an <dependency> tag for that assembly. Each file in the manifest has an associated hash that ClickOnce uses to determine if the file has changed. Actually, the hash is used for two things: 1) to determine changes to a file and, 2) to detect file tampering.

If your build process recreates assemblies, even if they were not modified, then ClickOnce will not know that the two files are identical. ClickOnce determines changes to files by comparing the file hash on client with what's on the server (in the application manifest). If the two files have the same hash, then ClickOnce doesn't download the file again, it simply copies the file from one directory to another.

There are several things to think about when you start to build an automated ClickOnce deployment.

1. Identify any 3rd party assemblies and be sure not to rebuild these files; put these files in a well-known folder and have the build process copy them.
2. If you have assemblies that you share across projects/solutions, establish a mechanism in your build process that will detect changes to files in these projects and will rebuild only when necessary.
3. The core of your application can be rebuild depending on how large the project is.

Generally, items 1) and 2) will make up a significant part of an application and needs to be addressed properly from the context of a ClickOnce deployment.

2/6/2006 8:58:46 AM (Eastern Standard Time, UTC-05:00) #    Comments [3]  |  Trackback

 

Source Control Tutorial#

Source-code management (SCM) is something we all deal with as developers. How we manage source code, however, is something we learn after entering the workforce. Developers are usually more interested in programming languages and tools, so they don’t pay too much attention to how will we protect our intellectual property. Recently I ran into an e-book by one of the principals of Vault (a VSS like source-code management system) and was very impressed. It’s definitely worth a read.

SCM
2/5/2006 7:32:12 PM (Eastern Standard Time, UTC-05:00) #    Comments [3]  |  Trackback

 

All content © 2009, Sayed Y. Hashimi
On this page
This site
Calendar
<January 2009>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567
Archives
Sitemap
Blogroll OPML
Disclaimer

Powered by: newtelligence dasBlog 1.8.5223.2

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail

Theme design by Jelle Druyts