Category Archives: Cruise Control .NET

Setting up Cruise Control . NET with TFS for ASP .NET Web Application

I have setup Cruise Control .NET from scratch very recently in integration with TFS 2010 for ASP .NET MVC3 application. I am writing down steps which I followed to set it up here –

1) Download Cruise Control .NET from this location and unzip it to use it.

2) Install .NET framework, IIS and NANT as well.

3) Add “WebDashboard” as an IIS application.

4) Update Dashboard.config file with admin password for CC dashboard.

<administrationPlugin password=”yourpassword” />

5) You can browse URL in IIS to check if dasboard is working fine. You can reach admin dashboard to install any required packages. For me loading http://localhost/ccnet/ViewFarmReport.aspx errored out for TCP connecton not made. It was happening because ccnet service was not running from “Server”. To make it run as background I used below VB script-

Set WshShell = CreateObject(“WScript.Shell”)WshShell.Run chr(34) & “C:\pathtoinstallfolder\Server\ccnet.exe” & Chr(34), 0Set WshShell = Nothing

(Run it with .vbs extension. Put above code and double click to execute it)

6) Create project in TFS 2010 and map it to local folder.

7) Edit “ccnet.config” to below in order to compile and publish website-

<cruisecontrol xmlns:cb=”urn:ccnet.config.builder”>

<project name=”Web Application” queue=”Q1″ queuePriority=”1″>

<sourcecontrol type=”vsts” autoGetSource=”true” applyLabel=”false”>

<server>TFS Server name till collection</server>

<project>Source Code path of TFS Project under collection</project>

<workingDirectory>Path to local working directory </workingDirectory>

<workspace>tfs server workspacename</workspace>

<cleanCopy>true</cleanCopy>

</sourcecontrol>

<tasks>

<msbuild>

<executable>C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe</executable>

<workingDirectory>Path to local working directory</workingDirectory>

<projectFile>MSBuild.xml</projectFile>

<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>

<targets>BuildAndPublish</targets>

<timeout>150</timeout>

<logger>C:\CruiseControl.NET-1.6.7981.1\Server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>

</msbuild>

</tasks>

<publishers>

<buildpublisher>

<sourceDir>Path to Site where we have published output with compilation</sourceDir>

<publishDir>Path to copy published site to IIS directory</publishDir>

<useLabelSubDirectory>false</useLabelSubDirectory>

<alwaysPublish>false</alwaysPublish>

</buildpublisher>

<xmllogger logDir=” path to logs” />

</publishers>

</project>

</cruisecontrol>

8) Create MSBuild.xml and put below code. I have customized this according to my web application under same TFS location which we are referring in same ccnet.config-

<Project DefaultTargets=”BuildAndPublish” xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″&gt;

<PropertyGroup>

<SolutionPath>Path to source code or solution folder</SolutionPath>

<OutputPath>Path to output directory</OutputPath>

</PropertyGroup>

<ItemGroup><testwebapplicationBin Include=”$(SolutionPath)\testwebapplication\bin\**\*.*” /></ItemGroup>

<Target Name=”CleanTarget”>

<Message Text=”Removing all source files from $(OutputPath)” />

<RemoveDir Directories=”$(OutputPath)\_PublishedWebsites\” />

<RemoveDir Directories=”$(OutputPath)\” /></Target><Target Name=”BuildAndPublish”>

<MSBuild Projects=”$(SolutionPath)\testwebapplication.sln” Targets=”Clean;Build” />

<CallTarget Targets=”CleanTarget” />

<MSBuild Projects=”$(SolutionPath)\testwebapplication\testwebapplication.csproj” Targets=”_CopyWebApplication;_BuiltWebOutputGroupOutput” Properties=”OutDir=$(OutputPath)\” />

<Copy SourceFiles=”@(testwebapplicationBin)” DestinationFolder=”$(OutputPath)\_PublishedWebsites\testwebapplication\bin\%(RecursiveDir)” />

</Target>

</Project>

(Note: I have used testwebapplication everywhere because I created testwebapplication project in tfs 2010, change name according to your project)9) Go to Dashboard and Click Force Build to compile and deploy code in IIS.10) You might also need to install AJAX 1.0 or ASP .NET MVC 3.0 to make your website work in IIS. Also, you need to give “Users” as full access if you are using IIS 7.0 on Windows 7. If any dll reference is missing while running site in IIS, then you can change “Copy Local” to true from TFS 2010 Project to make it working.

Advertisements

Sample CCNET nightly scheduled build

Hi

Recently I have developed nightly scheduled build for cruise control .net dashboard. Below is sample project where version polling will happen at 4 pm and if changes are there other then builduser account then build will be triggered. I have also created recently plugin to accommodate whether and ion what case build label should increase.

<cb:scope ProjectName=”Project Build” TargetName=”Main” SharedPath=”\\mymachine\sharedpath”>

<project name=”$(ProjectName)”

description=”This is for compiling and creating build of Project” showStartStopButton=”false” askForForceBuildReason=”required”>

<triggers>

<!–<scheduleTrigger time=”11:30″ buildCondition=”ForceBuild” name=”Nightly Scheduled”>–>

<scheduleTrigger time=”16:00″ buildCondition=”IfModificationExists” name=”Nightly Scheduled”>

<weekDays>

<weekDay>Monday</weekDay>

<weekDay>Tuesday</weekDay>

<weekDay>Wednesday</weekDay>

<weekDay>Thursday</weekDay>

<weekDay>Friday</weekDay>

<weekDay>Saturday</weekDay>

<weekDay>Sunday</weekDay>

</weekDays>

</scheduleTrigger>

</triggers>

<category>Nightly Scheduled Build</category>

<labeller type=”sharedLabeller”>

<sharedLabelFilePath>E:\Program Files\CruiseControl.NET\server\buildnumber.txt</sharedLabelFilePath>

<buildSuccessFile>E:\Program Files\CruiseControl.NET\server\buildSuccessFile.txt</buildSuccessFile>

<alwaysincrement>yes</alwaysincrement>

</labeller>

<sourcecontrol type=”filtered”>

<sourceControlProvider type=”vsts” autoGetSource=”false” applyLabel=”false”>

<server>http://tfs01:8080/tfs/projectoffice</server&gt;

<project>$/Project/Main</project>

<workingDirectory>E:\Project\Main</workingDirectory>

<cleanCopy>true</cleanCopy>

<workspace>mymachineworkingcopy</workspace>

<force>false</force>

<executable>C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe</executable>

<username>builduser</username>

<password>password</password>

</sourceControlProvider>

<exclusionFilters>

<userFilter>

<names>

<name>builduser</name>

</names>

</userFilter>

</exclusionFilters>

</sourcecontrol>

 

<tasks>

<modificationHistory onlyLogWhenChangesFound=”true” />

<modificationWriter>

<filename>Modifications.$(buildlabel).xml</filename>

<path>C:\Data</path>

<appendTimeStamp>False</appendTimeStamp>

</modificationWriter>

<nant>

<executable>C:\Program Files\NANT\bin\nant.exe</executable>

<baseDirectory>E:\saratoga\ga\Main\BuildScripts_CCNET</baseDirectory>

<buildArgs>-D:outputType=Xml -D:BuildType=”Full” -D:branchname=”Main”</buildArgs>

<nologo>false</nologo>

<buildFile>BuildMain.build</buildFile>

<targetList>

<target>$(TargetName)</target>

</targetList>

<buildTimeoutSeconds>200000</buildTimeoutSeconds>

</nant>

<modificationReader>

<deleteAfterRead>false</deleteAfterRead>

<filename>Modifications.$(buildlabel).xml</filename>

<path>C:\Data</path>

</modificationReader>

</tasks>

<publishers>

<xmllogger />

<artifactcleanup cleanUpMethod=”KeepLastXBuilds”

cleanUpValue=”50″ />

<email from=”mygroup@mydomain.com” mailhost=”serverhost.com” includeDetails=”TRUE”>

<users>

<user name=”Myteam” group=”myteam” address=”groupemail@mydomain.com”/>

</users>

<groups>

<group name=”Myteam”>

<notifications>

<notificationType>Always</notificationType>

</notifications>

</group>

 

</groups>

<subjectSettings>

<subject buildResult=”Success” value=”$(ProjectName) $(buildlabel) is available @ $(SharedPath)” />

<subject buildResult=”Fixed” value=”$(ProjectName) $(buildlabel) is now fixed and available @ $(SharedPath)” />

<subject buildResult=”StillBroken” value=”$(ProjectName) is still broken, the fix tried has failed.” />

<subject buildResult=”Broken” value=”$(ProjectName) broke for $(buildlabel). Refer buildlogs for complete log file to see exact reason”  />

<subject buildResult=”Exception” value=”Network / source control / System problem for $(ProjectName).” />

</subjectSettings>

<xslFiles>

<file>xsl\header.xsl</file>

<file>xsl\compile.xsl</file>

</xslFiles>

<attachments>

<file>C:\Data\KeyFile.txt</file>

<file>C:\Data\Modifications.$(buildlabel).txt</file>

</attachments>

</email>

</publishers>

</project>

</cb:scope>

Shared Label Plugin for CCNET

Recently, i have to develop plugin to share the build label across CCNET projects depending upon previously success or failure build. So, I came up with below solution in C#-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ThoughtWorks.CruiseControl.Core;
using ThoughtWorks.CruiseControl.Remote;
using System.IO;
using Exortech.NetReflector;

namespace ThoughtWorks.CruiseControl.Core.labeller
{

// this is the labeller name that will be used in  ccnet.config
[ReflectorType(“sharedLabeller”)]
public class SharedLabeller : ILabeller
{
[ReflectorProperty(“sharedLabelFilePath”, Required = true)]
public string sharedLabelFilePath { get; set; }

[ReflectorProperty(“buildSuccessFile”, Required = true)]
public string buildSuccessFile { get; set; }

[ReflectorProperty(“alwaysincrement”, Required = true)]
public string alwaysincrement { get; set; }

#region ILabeller Members

public string Generate(IIntegrationResult previousResult)
{
if (ShouldIncrementLabel(previousResult))
return IncrementLabel();

if (previousResult.Status == IntegrationStatus.Unknown)
return “0”;

return previousResult.Label;
}

public void Run(IIntegrationResult result)
{
result.Label = Generate(result);
}

#endregion

private string IncrementLabel()
{
if (!File.Exists(sharedLabelFilePath))
return “0”;

using (FileStream fileStream = File.Open(sharedLabelFilePath,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None))
{
// read last build number from file
var bytes = new byte[fileStream.Length];
fileStream.Read(bytes, 0, bytes.Length);

string rawBuildNumber = Encoding.ASCII.GetString(bytes);

// parse last build number
int previousBuildNumber = int.Parse(rawBuildNumber);
int newBuildNumber=0;
if (File.Exists(buildSuccessFile) && alwaysincrement==”yes”)
newBuildNumber = previousBuildNumber + 1;
else
newBuildNumber=previousBuildNumber;

// increment build number and write back to file
bytes = Encoding.ASCII.GetBytes(newBuildNumber.ToString());

fileStream.Seek(0, SeekOrigin.Begin);
fileStream.Write(bytes, 0, bytes.Length);

return newBuildNumber.ToString();
}
}

private static bool ShouldIncrementLabel(IIntegrationResult previousResult)
{
return (previousResult.Status == IntegrationStatus.Success || previousResult.Status == IntegrationStatus.Unknown);
}
}
}