ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

You can setup continuous integration and automated deployment for your web application using CruiseControl.NET, Subversion, MSBuild and Robocopy. I will show you how you can automatically build the entire solution, email build report to developers and QA, deploy latest code in IIS all using CruiseControl.NET every N minutes.

First get the following:

  • CruiseControl.NET
  • Subversion (install the command line tools and add the Subversion bin path to PATH environment variable)
  • Robocopy (Windows Vista/2008 has it built-in, here's the link for Windows 2003)
  • Install .NET Framework. You need it for MSBuild.

You will learn how I have configured Continuous Integration and Deployment for my open source AJAX Portal project www.Dropthings.com. The code is hosted at CodePlex. When some developer makes a commit, CruiseControl downloads the latest code, builds the entire solution, emails build report and then deploys the latest web site to IIS 6.0.

After installing CruiseControl.NET, go to Programs -> Cruise Control -> CruiseControl.NET Config.

Now keep copying and pasting the following XML blocks and make sure you understand each block and make necessary changes:

   1: <cruisecontrol>
   2:     <project name="Dropthings" queue="DropthingsQueue" queuePriority="1">
   3:         <!-- 
   4:         Path to the trunk folder where the full solution starts from. This is where
   5:         subversion checkout and incremental update is performed 
   6:         -->
   7:         <workingDirectory>d:\cc\dropthings\code\trunk\</workingDirectory>
   8:         <!-- Some path where CCNet writes its logs and stuffs. It can be outside the log folder -->
   9:         <artifactDirectory>d:\cc\dropthings\artifact\</artifactDirectory>
  10:         <category>Dropthings</category>
  11:         <!-- CCNet installs a web dashboard. Enter the URL of that dashboard here -->
  12:         <webURL>http://localhost/ccnet/</webURL>
  13:         <modificationDelaySeconds>60</modificationDelaySeconds>
  14:         <labeller type="defaultlabeller">
  15:             <prefix>0.1.</prefix>
  16:             <incrementOnFailure>true</incrementOnFailure>
  17:             <labelFormat>000</labelFormat>
  18:         </labeller>
  19:         <state type="state" directory="State" />

First change the working directory. It needs to be the path of the folder where you will have the solution downloaded. I generally create folder structure like this:

  • D:\CC - Root for all CC.NET enabled projects
    • \ProjectName - Root project folder
      • \Code - Code folder where code is downloaded from subversion
      • \Artifact - CC.NET generates a lot of stuff. All goes here.

Next comes the Subversion integration block:

   1: <sourcecontrol type="svn">
   2:     <!-- Subversion trunk repository to keep checking for latest code -->
   3:     <trunkUrl>http://localhost:8081/tfs02.codeplex.com/dropthings/trunk</trunkUrl>
   4:     <workingDirectory></workingDirectory>
   5:     <username>***** SUBVERSION USER NAME *****</username>
   6:     <password>***** SUBVERSION PATH *****</password>
   7: </sourcecontrol>

Here specify the subversion location where you want to download code to the working folder. You should download the entire solution because you will be building the entire solution using MSBuild soon.

I left <workingDirectory> empty. This means whatever is specified earlier in the <workingDirectory> is used. Otherwise you can put some relative folder path here or any absolute folder.

Now we start building the tasks that CC.NET executes - Build, Email, and Deploy.

   1: <tasks>
   2:     <artifactcleanup   cleanUpMethod="KeepLastXBuilds"   cleanUpValue="5" />
   3:     <modificationWriter>
   4:         <filename>mods.xml</filename>
   5:         <path></path>
   6:     </modificationWriter>
   7:  
   8:     <!-- MSBuild task to build a .msbuild file that basically builds a .sln file -->
   9:     <msbuild>
  10:         <executable>C:\windows\Microsoft.NET\Framework64\v3.5\MSBuild.exe</executable>
  11:         <workingDirectory></workingDirectory>
  12:         <projectFile>Dropthings.msbuild</projectFile>
  13:         <targets>Build</targets>
  14:         <timeout>300</timeout>
  15:         <logger>C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
  16:     </msbuild>

This block first says, keep artifacts for last 5 build and remove olders. Artifacts are like build reports, logs etc. You can increase the value for longer history.

Then the most important <msbuild> task. The executable path is to the MSBuild.exe. I am using .NET 3.5 Framework 64bit edition. You might have .NET 2.0 and 32bit version. So, set the right path here for the MSbuild.exe.

<projectFile> maps to a MSBuild file. It's a skeleton MSBuild file which basically says build this Visual Studio solution file. Here's how the msbuild file looks like:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Build"> 
    <!-- Rebuild entire solution -->
    <MSBuild Projects="Dropthings.sln" Targets="Rebuild" />
  </Target>
</Project>

The Dropthings.msbuild and Dropthings.sln file exists in the same trunk folder. This file says - build Dropthings.sln and do a rebuild.

Now you got the build done. Next is to deploy it. You will be using robocopy to copy files from the code folder to a destination folder which is mapped in IIS to a website. Robocopy will do a synchronization of the directories. It will add new files, overwrite old files and removes files from destination folder which no longer exists in the source folder.

Before you can deploy, you need to stop the website or restart IIS. Otherwise some files may be in use and you will not be able to delete or overwrite the files. Here's how to stop IIS using the iisreset command line tool:

<!-- 
Stop IIS before copying over the latest web project files so that there's no write lock and IIS does not
start restarting the site half way through
-->
<exec>
    <executable>iisreset</executable>
    <buildArgs>/stop</buildArgs>
</exec>

If you do not want to stop the entire IIS, instead just stop a website and recycle an application pool, you can use the iisweb.vbs script for stopping a website and iisapp.vbs script for recycling application pool. Here's an example:

<exec>
    <executable>iisweb</executable>
    <buildArgs>/stop "Dropthings"</buildArgs>
</exec>
 
<exec>
    <executable>iisapp</executable>
    <buildArgs> /a "Dropthings" /r</buildArgs>
</exec>

You need to first register cscript as the default script runtime. In order to do this, go to command line and enter iisweb. It will tell you that it cannot use wscript to run this script and it needs to make cscript default. Let it make cscript as default.

Now the time to do the deployment of latest web site files. The following task launches robocopy to do the deployment:

<!--
Sync the web project folder with the deployment folder. The deployment folder is where IIS
is mapped to serve the site. The deployment folder is at the buildArgs node. The robocopy 
utility does an exact sync, adding new files, updating old files, deleting files that no longer
exist.
-->
<exec>
    <!--<executable>C:\Program Files (x86)\Windows Resource Kits\Tools\robocopy.exe</executable>-->
    <executable>robocopy.exe</executable>
    <baseDirectory>Dropthings\</baseDirectory>
    <buildArgs>.\ d:\cc\Dropthings\Deploy *.* /E /XA:H /PURGE /XO /XD ".svn" /NDL /NC /NS /NP</buildArgs>
    <buildTimeoutSeconds>60</buildTimeoutSeconds>
    <successExitCodes>1,0</successExitCodes>
</exec>

First you need to correct the robocopy.exe path. For Windows Vista/Windows 2008, keep it as it is. For Windows 2003, you need to specify the full path. You also need to remove the (x86) from the path if you have 32bit OS.

Next is the <baseDirectory>. This is relative to the working directory. It's the path of the website folder. Dropthings website folder is located under the Dropthings folder under trunk. So, I have specified Dropthings\ as the subfolder where the website files are located. You need to specify your project's website folder's relative path here form the <workingDirectory>.

Next change the path in the <buildArgs> node. First one is the source ".\" which you keep as it is. It means copy files from the baseDirectory. Next is the absolute path to the deployment folder where the web site is mapped in IIS. You can use both relative or absolute path here. While using relative path, just keep in mind the robocopy is running from the <workingDirectory>\<baseDirectory> folder.

After the path keep the *.* and the remaining flags intact. The flags mean:

  • Copy all subdirectories /E
  • Copy hidded files /XA:H
  • Do not copy old files /XO
  • Exclude .svn directory while copying files /XD ".svn"
  • Do not show list of files and directories being copie /NDL, /NC, /NP

After the deployment, you need to turn IIS back on or start the website that you stopped:

<!-- Turn IIS back on -->
<exec>
    <executable>iisreset</executable>
    <buildArgs>/start</buildArgs>
</exec>
 
<!--
<exec>
    <executable>iisweb</executable>
    <buildArgs>/start "Dropthings"</buildArgs>
</exec>            
-->

Now we got the build and deployment done. Next is to email a nice report to developers and QA. If build succeeds, email both developers and QA so that they can check out the latest build. But if build fails, email only developers.

<publishers>
    <rss/>
    <xmllogger />
    <statistics />
 
    <!-- Email build report to development and QA team -->
    <email from="admin@yourcompany.com" mailhost="localhost" mailport="25" includeDetails="TRUE"
           mailhostUsername="" mailhostPassword="" useSSL="FALSE">
 
        <users>
            <user name="Developer1" group="devs" address="dev1@yourcompany.com"/>
            <user name="Developer2" group="devs" address="dev2@yourcompany.com"/>
            <user name="Developer3" group="devs" address="dev3@yourcompany.com"/>
            
            <user name="QA1" group="qa" address="qa1@yourcompany.com"/>
            <user name="QA2" group="qa" address="qa2@yourcompany.com"/>
            <user name="QA3" group="qa" address="qa3@yourcompany.com"/>                    
            
        </users>
 
        <groups>
            <group name="devs" notification="Always"/>
            <group name="qa" notification="Success"/>
        </groups>
 
        <converters>
            <!--<regexConverter find="$" replace="@dropthings.com" />-->
        </converters>
 
        <modifierNotificationTypes>
            <NotificationType>Always</NotificationType>
        </modifierNotificationTypes>
 
    </email>
    <modificationHistory  onlyLogWhenChangesFound="true" />
</publishers>

First you need to change the <email> tab where you specify the from address, mail server name, and optionally a user account for the email address that you need to use to send out emails.

Then edit the <users> node and put your developers and QA.

That's it! You got the configuration file done. Next step is to launch the CruiseControl.NET from Programs -> CruiseControl.NET -> CruiseControl.NET. It will launch a process that will execute the tasks according to the configuration. On Windows Vista, you will have to run it with Administrative privilege.

There's also a Windows Service that gets installed. It's named CruiseControl.NET. You can start the service as well on a server and go to sleep. It will do continuous integration and automated deployment for you.

There's also a web based Dashboard that you can use to force a build or stop a build or see detail build reports.

image

You can create multiple projects. You can have one project to build trunk code only, but do no deployment. Then you can create another project to build, deploy some branch that's ready for production. You can create another project to build and deploy on QA server and so on.

Here's the full configuration file that you can use as your baseline.

 

kick it on DotNetKicks.com

Published Mon, Oct 6 2008 7:59 by omar
Filed under: , ,

Comments

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Monday, October 06, 2008 1:06 PM by Mitch

Hi Omar.

Just wanted to say thanks. I've been looking to do this for a while but have not done it due to the perceived learning curve. This article was a great way to get started for us.

Very nice of you to share your work with the community.

Cheers!

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Tuesday, October 07, 2008 11:20 AM by Pathik

This is really helpful article. I have heard that CIFactory is also doing great job in Continuous Integration. If you write something about that, it will also really help us.

thanks !!

Pathik

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Tuesday, October 07, 2008 6:27 PM by Adam Zochowski

When you want to auto deploy, why not use web deployment project?

hxxp://msdn.microsoft.com/en-us/asp.net/aa336619.aspx

secondly, you have not touched upon testing.  I have toyed with automating FxCop

hxxp://msdn.microsoft.com/en-us/library/bb429476(VS.80).aspx

ccnet.config changes:

 <executable>c:\Program Files (x86)\Microsoft FxCop 1.36\fxcopcmd</executable>

    <baseDirectory>c:\Projects\myProject\</baseDirectory>

    <buildArgs> /file:application\bin\mydll.dll /o:ccnet-fxcop.xml</buildArgs>

    <buildTimeoutSeconds>100</buildTimeoutSeconds>

</exec>

<merge>

 <files>

<file>c:\Projects\myProject\ccnet-fxcop.xml</file>

</files>

     </merge>

dashboard.config changes:

                   <xslFile>xsl\fxcop-summary.xsl</xslFile>

                   <xslFile>xsl\fxcop-summary2.xsl</xslFile>

...

           <xslReportBuildPlugin description="FxCop Clean" actionName="FxCopBuildReport2" xslFileName="xsl\FxCop2.xsl" />            

           <xslReportBuildPlugin description="FxCop Buggy"   actionName="FxCopBuildReport" xslFileName="xsl\FxCopReport.xsl" />            

----

Have not time to do nUnit ( hxxp://www.nunit.org/ ) and or SandCastle ( hxxp://blogs.msdn.com/sandcastle/ ) integrations yet

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Wednesday, October 08, 2008 2:33 AM by GClover

Hi Omar.

Dropthings.com is a wonderful website, but I found a bug recently, not a serious one, but I think you might be interested.

Here is the bug:

When I add a new stuff in a tab, for example "How to the Day". Assume that I have two other widget in this tab already:BBC & CNN, with the order that CNN located under BBC, both in the same column. Now I drag the new widget "How to the Day " to the bottom of the column,(the same column with BBC & CNN) and we have the order: BBC, CNN and then How to the Day, the same order I was expected after I refreshed this page. After I made a refresh, however, the order comes out like: BBC, How to the Day and then CNN, which means the new widget I dragged moved upward after refreshment.

Hope you can check it out.

:)

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Thursday, October 09, 2008 4:59 PM by Noman

This is great! I've seen a lot of examples using VSS but this is what I was looking for. I need to book mark this page. I will go forward with this and hope thtis helps me!

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Monday, October 13, 2008 5:16 AM by Milan Lamichhane

Omar,

Nice post. But how about the database changes? I would also like to run database scripts on the server while deploying the application. Any idea?

Thanks in advance.

Milan

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Monday, October 13, 2008 10:34 AM by Altug Sahin

Hi Omar,

How do you configure and deploy for different builds such as "debug" and "release"?

Connection strings and different environment settings should be picked up in those builds so how would you achieve that?

Thanks

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Thursday, October 23, 2008 7:11 PM by Eric Swanson

Awesome! I read your book when it released and loved it. Keep up the great work!

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Wednesday, November 12, 2008 1:56 PM by Pathik

excellent article. I have added aspnet_compiler within msbuild but somehow its not working. How if you can give some hint on that too ??? It has some problem with webconfig saying "MachineToApplication" setting has problem, I searched for solution and it says if I have multiple web config, but my project has only 1 web config.

Please throw some light on that.

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Sunday, January 04, 2009 3:45 PM by Gary Woodfine

Just going through your tutorial, thought I would just point out that you are missing some closing tags in your XML. This may lead to some confusion to newbies who are copying and pasting your code to have a look ( it did confuse me :-) )

Otherwise I enjoyed it and it helped me get something going.

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Thursday, January 22, 2009 10:17 AM by Naveen

Hi

Its great article, but i have some more question to you is that how we can deploy the build code to different server i.e. QA, prod.

What is best way to deploy to different server in your advice plz

nlohchab@aim.com

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Wednesday, January 28, 2009 3:09 PM by Naveen

Hi Omar,

I asked you earlier also in my comments the query i have regarding the deployment process with robocopy on to our different environment i.e. QA and dev servers(machines) After build : I need to deploy my latest code to other staging servers automatically with CruiseControl as I am using MSBuild, CruiseControl.net, SVN, and off course want to use robocopy for the deployment. if possible could you guys explain me a bit more about it, ccnet.config file will me really helpfull with bit explaination. As i ahve to copy my latest build from different location (multiple files)and as I already says to copy in specific directories on other environment.

I really appericiate yor help and direction in this matter.

Gary mention in his previos remarks that blog missed some xml in blog description, plz as i am also new to CI, guide me in that regard as well.

Thanks

nlohchab@aim.com

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Sunday, February 08, 2009 6:21 AM by Miodrag

Hi,

What's about CVS' integration?

Is it possible? Is it similar to Subversion's?

Regards,

Miodrag

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Friday, March 20, 2009 12:58 PM by Rich

When runnig iisweb, you need to do this:

<exec>

<executable>cmd.exe</executable>    <buildArgs>/c iisweb /stop "Dropthings"</buildArgs>

</exec>

or you get errors when attempting to execute the script.

Rich

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Friday, May 15, 2009 8:44 AM by sam

can any one plz suggest, how can we build and then publish using same scenario

# ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Sunday, October 11, 2009 8:06 PM by PimpThisBlog.com

Thank you for submitting this cool story - Trackback from PimpThisBlog.com

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Tuesday, January 12, 2010 7:30 PM by Tim

Good article still works today,

i had issues with the robocopy exit codes though, i needed to add 3 and 2 to the list since my build creates custom file names per build

# re: ASP.NET website Continuous Integration+Deployment using CruiseControl.NET, Subversion, MSBuild and Robocopy

Sunday, January 17, 2010 8:27 AM by Ferdous

Great Work Omar. Thanks.

Leave a Comment

(required) 
(required) 
(optional)
(required)