Dec 18 2009

Clean up unwanted svn folders with NAnt

Category: Agileryancmartin1976 @ 20:43

First Strategy:

Second Strategy:

If you ever had a corrupted Subversion repository on your local and the cleanup method wasn't working as it should. Your best bet most of the time depending on the size of the project is to delete all of the svn directories in it and start over fresh. This is a quick and dirty way to do that.

Delete all of svn directories in your project with 2 bat files and 1 NAnt build script.

Your folder structure should resemble something like this.

\ProjectName
    \Trunk
        \Binaries\NAnt
        \Build
        \Source

First you need to download NAnt and place it somewhere on the server where you are planning on doing the cleanup. I like to add a binaries directory under my trunk directory and place all of my executables there.

Next you need to create a new NAnt build script with one task and save it in the build directory as clean.build.

clean.build

<?xml version="1.0" encoding="utf-8"?>
<project name="CleanUp" default="build" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
  <property name="trunk.dir" value="..\" />
 
  <target name="clean" depends="clean.svn.folders" />
 
  <target name="clean.svn.folders">
    <echo message="Deleting all svn folders in directory"/>
    <delete>
      <fileset basedir="${trunk.dir}" defaultexcludes="false">
      <include name="**/.svn" />
      <include name="**/.svn/**/*" />
      </fileset>
    </delete>
  </target>
</project>

Now create two bat files with notepad

build.bat

..\Binaries\NAnt\bin\nant.exe -buildfile:clean.build %*

clickToBuild.bat

@echo off
:input
cls
set INPUT=
set TARGET=
echo Please choose from the following build options:
echo .
echo 1 = Clean
echo .
set /P INPUT=Please specify your option from above: %=%
if "%INPUT%"=="" goto input
if "%INPUT%"=="1" set TARGET="clean"
if "%TARGET%"=="" goto input
echo .
echo .
echo .
build.bat %TARGET% & pause

Now you should have these files

  • Trunk\Build\clean.build
  • Trunk\Build\build.bat
  • Trunk\Build\clickToBuild.bat
  • Trunk\Binaries\Nant\Nant.exe

Now click on the bat file called clickToBuild.bat and select the number 1 to run and that’s it! All of the directories under your trunk named .svn will be deleted.

Tags: , ,

Dec 16 2009

Overview of the Facade Design Pattern

Category: Design Patternryancmartin1976 @ 17:50

First Strategy:

Second Strategy:

Façade Design Pattern in C#

The Façade pattern is sometimes called and written as a class manager. It's an easy way to organize and unify numerous classes usually within the same namespace and design structure.

The Façade pattern is a high level object pulling together low level objects for simplifying application complexity.

public class Evaluate

{

    public int SubmitForm()

  {

        List<IProduct> products = new List<IProduct>();

      string productToEval = "premium";

        switch (productToEval)

        {

            case "standard":

                products.Add(new StandardProduct());

                break;

            case "premium":

                products.Add(new PremiumProduct());

                break;

            case "substandard":

                products.Add(new SubStandardCentralProduct());

                products.Add(new SubStandardRemoteProduct());

                break;

            case "distributed":

                products.Add(new DistributedCentralProduct());

                products.Add(new DistributedRemoteProduct());

                break;

        }

 

        /////////////////////////////////////////////

        // THEN ADD PLUGIN PRODUCT

        /////////////////////////////////////////////

        products.Add(new IntegratedProduct(false));

        products.Add(new ExternalProduct(false));

        products.Add(new DiscontinuedProduct(false));

 

        EvalFacade evalFacade = new EvalFacade(products, userInfo);

        return evalFacade.Run();

  }

}

 

public class EvalFacade

{

    private List<IProduct> _products;

    private UserInfo _userInfo;

 

    private string _parentSerialNumber = "";

    public string ParentSerialNumber

    {

        get { return _parentSerialNumber; }

        set { _parentSerialNumber = value; }

    }

 

    public EvalFacade(List<IProduct> products, UserInfo userInfo)

    {

        _products = products;

        _userInfo = userInfo;

    }

 

    public int Run()

    {

        int status = 0;

        foreach (IProduct product in _products)

        {

            if (product != null)

            {

                product.AddLicense(_userInfo, this.ParentSerialNumber);

                status = product.AddLicenseStatus(_userInfo);

                if (status != 0)

                    return status;

                product.AddLeadIntoCRM(_userInfo, this.ParentSerialNumber);

                if (string.IsNullOrEmpty(this.ParentSerialNumber) && !string.IsNullOrEmpty(product.SerialNumber))

                    this.ParentSerialNumber = product.SerialNumber;

            }

        }

        return status;

    }

}

Tags:

Dec 16 2009

Overview of the Chain of Responsibility Design Pattern

Category: Design Patternryancmartin1976 @ 17:41

First Strategy:

Second Strategy:

Chain of Responsibility Design Pattern in C#

This pattern decouples events from the sender object to the receiver object. The sender and receiver are linked together and hieratical, hence the name chain of responsibility.

What does that mean?

We have three objects that are linked and communicate with one another. One object passes an event to the next object until one of those objects can satisfy the event being passed.

Dog, Bird, Fish all derive from Animal but only one of them can run but all of them can move. We would have a move method which could have a run event which the Dog object could execute perfectly.

public interface IProduct

{

    void AddLicense(UserInfo userInfo, string parentSerialNumber);

    int AddLicenseStatus(UserInfo userInfo);

    void AddLeadIntoCRM(UserInfo userInfo, string parentSerial);

}

 

public class PremiumProduct : IProduct

{

    private ILicense _license;

    private ILogging _logging;

 

    public PremiumProduct()

    {

        _license = new ParentLicense();

        _logging = new ParentLogging();

    }

 

    public virtual void AddLicense(UserInfo userInfo, string parentSerialNumber)

    {

        _license.AddLicense(this, userInfo, parentSerialNumber);

    }

 

    public virtual int AddLicenseStatus(UserInfo userInfo)

    {

        return _license.AddLicenseStatus(this, userInfo);

    }

 

    public virtual void AddLeadIntoCRM(UserInfo userInfo, string parentSerial)

    {

        _logging.AddLeadIntoCRM(this, userInfo, parentSerial);

    }

}

 

public class VoIPProduct : IProduct

{

    private ILicense _license;

    private ILogging _logging;

    private bool _logLead = false;

 

    public VoIPProduct()

    {

        _license = new PluginLicense();

        _logging = new PluginLogging();

    }

 

    public VoIPProduct(bool logLead)

    {

        _license = new PluginLicense();

        _logging = new PluginLogging();

        _logLead = logLead;

    }

 

    public virtual void AddLicense(UserInfo userInfo, string parentSerialNumber)

    {

        _license.AddLicense(this, userInfo, parentSerialNumber);

    }

 

    public virtual int AddLicenseStatus(UserInfo userInfo)

    {

        return _license.AddLicenseStatus(this, userInfo);

    }

 

    public virtual void AddLeadIntoCRM(UserInfo userInfo, string parentSerial)

    {

        if (_logLead)

            _logging.AddLeadIntoCRM(this, userInfo, parentSerial);

    }

}

 

public interface ILicense

{

    void AddLicense(IProduct product, UserInfo userInfo, string parentSerialNumber);

    int AddLicenseStatus(IProduct product, UserInfo userInfo);

}

 

public interface ILogging

{

    void AddLeadIntoCRM(IProduct product, UserInfo userInfo, string parentSerial);

}

 

public class ParentLicense : ILicense

{

    public virtual void AddLicense(IProduct product, UserInfo userInfo, string parentSerialNumber)

    {

        webService.webService service = new webService.webService();

        string offerNumber = "XXXX-XXXX";

        string createLicense = service.AddLicense(offerNumber, "");

        string serialNumber = createLicense;

        product.SerialNumber = serialNumber.Remove(15, 8);

    }

 

    public virtual int AddLicenseStatus(IProduct product, UserInfo userInfo)

    {

        if (product.SerialNumber.ToLower().Contains("error"))

        {

            Utility.CreateErrorEmail(product, userInfo);

            return 5;

        }

        return 0;

    }

}

 

public class PluginLicense : ILicense

{

    public virtual void AddLicense(IProduct product, UserInfo userInfo, string parentSerialNumber)

    {

        webService.webService service = new webService.webService();

        string offerNumberPlugin = "XXXX-XXXX";

        string createLicensePlugin = service.AddLicense(offerNumberPlugin, parentSerialNumber);

        string serialNumberPlugin = createLicensePlugin;

        product.SerialNumber = serialNumberPlugin.Remove(15, 8);

    }

 

    public virtual int AddLicenseStatus(IProduct product, UserInfo userInfo)

    {

        if (product.SerialNumber.ToLower().Contains("error"))

        {

            Utility.CreateErrorEmail(product, userInfo);

            return 1;

        }

        return 0;

    }

}

 

public class ParentLogging : ILogging

{

    public virtual void AddLead(IProduct product, UserInfo userInfo, string parentSerial)

    {

        string serial = product.SerialNumber;

        string productName = product.ProductName + " Evaluation";

        webService.webService service = new webService.webService();

        string response = service.InsertLead(

            serial, parentSerial, "", "", "", "", "",

            "", "", "", "", "", "", "", "", "", "",

            "", "", "", "", "", "", "", "", "", "",

            "", "", "");

    }

}

 

public class PluginLogging : ILogging

{

    public virtual void AddLead(IProduct product, UserInfo userInfo, string parentSerial)

    {

        string serial = product.SerialNumber;

        string productName = product.ProductName + " Evaluation";

        webService.webService service = new webService.webService();

        string response = service.InsertLead(

            serial, parentSerial, "", "", "", "", "",

            "", "", "", "", "", "", "", "", "", "",

            "", "", "", "", "", "", "", "", "", "",

            "", "", "");

    }

}

Tags:

Dec 16 2009

Overview of the Strategy Design Pattern

Category: Design Patternryancmartin1976 @ 17:01

First Strategy:

Second Strategy:

Strategy Design Pattern in C#

This is one of the most common design patterns used throughout software design.

The pattern has interchangeable child classes that derive from an abstract base class or an interface. The interface tells those classes what it is expecting for method signatures and properties.

public class Evaluate

{

    public void SubmitForm()

    {

        List<IProduct> products = new List<IProduct>();

        string productToEval = "premium";

        switch (productToEval)

        {

            case "standard":

                products.Add(new StandardProduct());

                break;

            case "premium":

                products.Add(new PremiumProduct());

                break;

            case "substandard":

                products.Add(new SubStandardCentralProduct());

                products.Add(new SubStandardRemoteProduct());

                break;

            case "distributed":

                products.Add(new DistributedCentralProduct());

                products.Add(new DistributedRemoteProduct());

                break;

        }

 

        products.Add(new IntegratedProduct(false));

        products.Add(new ExternalProduct(false));

        products.Add(new DiscontinuedProduct(false));

    }

}

 

public interface IProduct

{

    string BuildNumber { get; set; }

    string ProductName { get; set; }

 

    void AddLicense(UserInfo userInfo, string parentSerialNumber);

    int AddLicenseStatus(UserInfo userInfo);

 

    void AddLeadIntoCRM(UserInfo userInfo, string parentSerial);

}

 

public class PremiumProduct : IProduct

{

    private ILicense _license;

    private ILogging _logging;

 

    public PremiumProduct()

    {

        _license = new ParentLicense();

        _logging = new ParentLogging();

    }

 

    public virtual void AddLicense(UserInfo userInfo, string parentSerialNumber)

    {

        _license.AddLicense(this, userInfo, parentSerialNumber);

    }

 

    public virtual int AddLicenseStatus(UserInfo userInfo)

    {

        return _license.AddLicenseStatus(this, userInfo);

    }

 

    public virtual void AddLeadIntoCRM(UserInfo userInfo, string parentSerial)

    {

        _logging.AddLeadIntoCRM(this, userInfo, parentSerial);

    }

 

    public virtual string BuildNumber

    {

        get { return WebConfigurationManager.AppSettings["Premium_Build_Number"]; }

        set { }

    }

 

    public virtual string ProductName

    {

        get { return WebConfigurationManager.AppSettings["Premium_Product_Name"]; }

        set { }

    }

}

 

public class SubStandardRemoteProduct : IProduct

{

    private ILicense _license;

    private ILogging _logging;

 

    public SubStandardRemoteProduct()

    {

        _license = new RemoteLicense();

        _logging = new RemoteLogging();

    }

 

    public virtual void AddLicense(UserInfo userInfo, string parentSerialNumber)

    {

        _license.AddLicense(this, userInfo, parentSerialNumber);

    }

 

    public virtual int AddLicenseStatus(UserInfo userInfo)

    {

        return _license.AddLicenseStatus(this, userInfo);

    }

 

    public virtual void AddLeadIntoCRM(UserInfo userInfo, string parentSerial)

    {

        _logging.AddLeadIntoCRM(this, userInfo, parentSerial);

    }

 

    public virtual string BuildNumber

    {

        get { return WebConfigurationManager.AppSettings["SubStandard_Remote_Build_Number"]; }

        set { }

    }

 

    public virtual string ProductName

    {

        get { return WebConfigurationManager.AppSettings["SubStandard_Remote_Product_Name"]; }

        set { }

    }

}

 

public class ExternalProduct : IProduct

{

    private ILicense _license;

    private ILogging _logging;

    private bool _logLead = false;

 

    public ExternalProduct()

    {

        _license = new PluginLicense();

        _logging = new PluginLogging();

    }

 

    public ExternalProduct(bool logLead)

    {

        _license = new PluginLicense();

        _logging = new PluginLogging();

        _logLead = logLead;

    }

 

    public virtual void AddLicense(UserInfo userInfo, string parentSerialNumber)

    {

        _license.AddLicense(this, userInfo, parentSerialNumber);

    }

 

    public virtual int AddLicenseStatus(UserInfo userInfo)

    {

        return _license.AddLicenseStatus(this, userInfo);

    }

 

    public virtual void AddLeadIntoCRM(UserInfo userInfo, string parentSerial)

    {

        if (_logLead)

            _logging.AddLeadIntoCRM(this, userInfo, parentSerial);

    }

 

    public virtual string BuildNumber

    {

        get { return WebConfigurationManager.AppSettings["External_Build_Number"]; }

        set { }

    }

 

    public virtual string ProductName

    {

        get { return WebConfigurationManager.AppSettings["External_Product_Name"]; }

        set { }

    }

}

Tags:

Dec 15 2009

Integrating CruiseControl.NET in your build process

Category: Continuous Integrationryancmartin1976 @ 21:05

First Strategy:

Second Strategy:

Let CruiseControl.NET take care of the heavy lifting!

Automating your daily and nightly builds is the most effective process one can take from the agile methodology processes and procedures. It is also very easy to setup and configure. Once you have it in place, it is on rare occasions when you have to make edits or upgrades to the build process. You can almost say it is as easy as, set it and forget it.

CruiseControl.NET automates your automation of the build process. Download the executable from Source Forge and run the executable on the server where the build process will be run from.

Ok things to note:

The configuration file for CruiseControl.NET lives here C:\Program Files\CruiseControl.NET\server\ccnet.config and this is where you will tell CruiseControl.NET what tasks in the build process to monitor and at what intervals to run at and who to notify when the task is either successful or broke.

There are 2 types of tasks that can be run from the ccnet.config file. First is run directly which special commands that are built right into CruiseControl.NET and the other is calling NAnt build script to run external tasks. You have a lot more flexibility with writing build tasks in NAnt.

ccnet.config – cruise control internal tasks

This task checks subversion for any edits or updates to the server every 120 seconds. If one is found then CruiseControl.NET compiles the solution making sure that the code introduced did not break the build.

<project name="Build">
  <labeller type="defaultlabeller" />
  <webURL>http://localhost/ccnet/ViewFarmReport.aspx</webURL>
 
  <sourcecontrol type="filtered">
    <sourceControlProvider type="svn" autoGetSource="true">
      <executable>C:\Program Files\VisualSVN Server\bin\svn.exe</executable>
      <trunkUrl>http://domain.com/svn/ProjectName/trunk</trunkUrl>
      <workingDirectory>D:\Projects\compile\ProjectName\trunk</workingDirectory>
      <tagOnSuccess>false</tagOnSuccess>
      <tagBaseUrl>http://domain.com/svn/ProjectName/tags</tagBaseUrl>
      <username>rmartin</username>
      <password>********</password>
    </sourceControlProvider>
    <inclusionFilters>
      <pathFilter>
        <pattern>**/*.*</pattern>
      </pathFilter>
    </inclusionFilters>
  </sourcecontrol>
 
  <triggers>
    <intervalTrigger name="continuous" seconds="120" buildCondition="IfModificationExists" />
  </triggers>
 
  <publishers>
    <merge>
      <files>
        <file>C:\Program Files\CruiseControl.NET\server\Build\Artifacts\results.xml</file>
      </files>
    </merge>
    <xmllogger />
    <statistics />
    <email
      from="ProjectNameBuild@domain.com"
      mailhost="mail.domain.com" includeDetails="TRUE">
      <users>
        <user name="Ryan Martin" group="buildmaster" address="rmartin@domain.com"/>
        <user name="Some Guy" group="buildmaster" address="sguy@domain.com"/>
      </users>
      <groups>
        <group name="buildmaster" notification="always"/>
      </groups>
    </email>
  </publishers>
</project>

ccnet.config – nant external tasks

This task is an external task which is run by a nant build script that lives potentially on the build server. You can have your build script wherever you choose but I like to have it with the project and all of its dependencies (documentation, binaries, database scripts and build scripts and reports).

<project name="Deploy-To-Development">
  <labeller type="defaultlabeller" />
  <webURL>http://localhost/ccnet/ViewFarmReport.aspx</webURL>
 
  <sourcecontrol type="filtered">
    <sourceControlProvider type="svn" autoGetSource="true">
      <executable>C:\Program Files\VisualSVN Server\bin\svn.exe</executable>
      <trunkUrl>http://domain.com/svn/ProjectName/trunk</trunkUrl>
      <workingDirectory>D:\Projects\compile\ProjectName\trunk</workingDirectory>
      <tagOnSuccess>false</tagOnSuccess>
      <tagBaseUrl>http://domain.com/svn/ProjectName/tags</tagBaseUrl>
      <username>rmartin</username>
      <password>Madison1</password>
    </sourceControlProvider>
    <inclusionFilters>
      <pathFilter>
        <pattern>**/*.*</pattern>
      </pathFilter>
    </inclusionFilters>
  </sourcecontrol>
 
  <tasks>
    <nant>
      <executable>D:\Projects\compile\ProjectName\trunk\binaries\nant\bin\nant.exe</executable>
      <baseDirectory>D:\Projects\compile\ProjectName\trunk\source\</baseDirectory>
      <buildArgs>-D:svn.executable="D:\Projects\compile\ProjectName\trunk\binaries\subversion\svn.exe"</buildArgs>
      <nologo>false</nologo>
      <buildFile>D:\Projects\compile\ProjectName\trunk\Build\ProjectName.build</buildFile>
      <targetList>
        <target>deploy-to-development</target>
      </targetList>
      <buildTimeoutSeconds>1200</buildTimeoutSeconds>
    </nant>
  </tasks>
 
  <publishers>
    <merge>
      <files>
        <file>C:\Program Files\CruiseControl.NET\server\Deploy-To-Development\Artifacts\results.xml</file>
      </files>
    </merge>
    <xmllogger />
    <statistics />
    <email
      from="ProjectNameBuild@domain.com"
      mailhost="mail.domain.com" includeDetails="TRUE">
      <users>
        <user name="Ryan Martin" group="buildmaster" address="rmartin@domain.com"/>
      </users>
      <groups>
        <group name="buildmaster" notification="always"/>
      </groups>
    </email>
  </publishers>
</project>

ProjectNameWeb.build – nant build script

This script has endless capabilities. There is an extensive set of commands you can call within nant scripts that are specific to nant build process. The command such as exec, echo, delete and copy are easy to learn and understand and most of all extremely powerful in helping cut down on development time by automating everyday remedial tasks.

<?xml version="1.0" encoding="utf-8"?>
<project name="IpswitchftWeb" default="build" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
  <!-- Properties -->
  <property name="devserver.website.dir" value="D:\Projects\www\ProjectName"/>
  <property name="trunk.dir" value="..\" />
  <property name="source.dir" value="${trunk.dir}\Source" />
  <property name="msbuild.exe" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe" />
  <property name="solution.sln" value="${source.dir}\ProjectNameWeb.sln" />
 
  <!-- Called Externally -->
  <target name="build" depends="compile" />
  <target name="deploy-to-development" depends="compile, deploy.to.development" />
 
  <!-- Coding Tasks -->
  <target name="compile">
    <exec program="${msbuild.exe}" commandline="${solution.sln} /t:Rebuild /v:q" />
  </target>
 
  <target name="deploy.to.development">
    <echo message="Deleting all files in development web directory"/>
    <delete verbose="true">
      <fileset basedir="${devserver.website.dir}">
        <include name="*.*" />
      </fileset>
    </delete>
 
    <echo message="XCopy files to development web directory"/>
    <copy todir="${devserver.website.dir}" includeemptydirs="false" overwrite="true">
      <fileset basedir="${ProjectNameWeb.dir}">
        <exclude name="**/obj/**"/>
        <exclude name="**/*.csproj"/>
        <exclude name="**/*.csproj*"/>
        <exclude name="**/App_Data*"/>
        <exclude name="**/App_Data*/**"/>
        <exclude name="**/.svn*"/>
        <exclude name="**/.svn*/**"/>
        <include name="**"/>
      </fileset>
    </copy>
  </target>
</project>

CruiseControl.NET Web Dashboard

This is a web interface to view and run CruiseControl.NET configuration file. From here you can run any task configured in your ccnet.config file and view the results.

This web page url defaults to the localhost setting but you will be viewing it from your local machine like other developers so you must change localhost with the server name: http://servername.domain.com/ccnet/ViewFarmReport.aspx

Tags: , , ,

Dec 15 2009

Integrate NUnit tests and results into CruiseControl.NET

Category: Continuous Integrationryancmartin1976 @ 21:04

First Strategy:

Second Strategy:

Integrating useful Unit Tests into CruiseControl.NET in ASP.NET Web Application

Unit tests can be a waste of time, especially if your writing them for every method looking for every possible way it could break. I found a very useful way to use unit tests in a project.

The entire project is data driven. All of the content lives in a database, even the page title, keywords and description.

This leaves a lot of room for possible failure points and unacceptable mistakes. Every page should have content on it, which goes without saying, but sometimes we forget to add the Meta data for pages thinking we will get back to it later and just forget. This is not a good scenario when the site depends heavily on SEO.

I have 4 projects:

  1. Web (UI)
  2. Core (Data Access)
  3. WebTests (UI Tests)
  4. CoreTests (Data Access Tests)

We are going to focus on the Web project and WebTests project.

Web project: Example web page that grabs content and Meta data from the database

About.aspx.cs

public partial class About : System.Web.UI.Page, IAbout
{
    private AboutPresenter _presenter;
    protected override void OnInit(EventArgs e)
    {
        _presenter = new AboutPresenter();
        _presenter.Init(this);
        _presenter.PerformLoad(MethodType.Page.Company_About.GetStringValue(),
                               null,
                               MethodType.Section.Main.GetStringValue());
    }
 
    public void LoadHtml(PageFT pageFt, PageContentFT pageContentFt)
    {
        if (pageFt == null)
        {
            Log.Error(this, "There is not any page details for this page.");
        }
        else if (pageFt.IsArchived)
        {
            Log.Error(this, "This page is archived and should not be allowed to be to viewed by users.");
        }
        else
        {
            BuildHeader(pageFt.Title, pageFt.Keywords, pageFt.Description);
            if (pageContentFt == null)
                Log.Error(this, "There is not any content for this page for the " + pageFt.Language + " language");
            else
                BuildPageContent(pageContentFt.PageContent);
        }
    }
 
    private void BuildHeader(string title, string keywords, string description)
    {
        litTitle.Text = "<title>" + title + " </title>";
        litKeywords.Text = "<meta name=\"keywords\" content=\"" + keywords + "\">";
        litDescription.Text = "<meta name=\"description\" content=\"" + description + "\">";
    }
 
    private void BuildPageContent(string pageContent)
    {
        litPageContent.Text = pageContent;
    }
}

AboutPresenter.cs

public class AboutPresenter
{
    private IAbout _view;
    private IUserSession _userSession;
    private IPageService _pageService;
    private IPageContentService _pageContentService;
 
    public void Init(IAbout view)
    {
        _view = view;
        _userSession = ObjectFactory.GetInstance<IUserSession>();
        _pageService = ObjectFactory.GetInstance<IPageService>();
        _pageContentService = ObjectFactory.GetInstance<IPageContentService>();
    }
 
    public void PerformLoad(string page, string lang, string section)
    {
        lang = string.IsNullOrEmpty(lang) ? _userSession.Culture : lang;
 
        if (string.IsNullOrEmpty(lang))
        {
            Log.Error(this, "Users browser culture is not getting passed in by method parameter or session variable.");
            lang = MethodType.Language.English.GetStringValue();
        }
 
        if (string.IsNullOrEmpty(page))
        {
            Log.Error(this, "Page name was not passed into the PerformLoad method which is needed.");
            return;
        }
 
        if (string.IsNullOrEmpty(section))
        {
            Log.Error(this, "Section name was not passed into the PerformLoad method which is needed.");
            return;
        }
 
        PageFT pageFt = _pageService.GetPageInfoByName(page, lang);
        PageContentFT pageContentFt = _pageContentService.GetPageContentBySection(page, lang, section);
        _view.LoadHtml(pageFt, pageContentFt);
    }
}

WebTests project: this unit test checks for a specific pages content and Meta data in all possible translated languages

AboutPresenterTester.cs

[TestFixture]
public class Company_About_Tester
{
    MockAboutPageView pageView = new MockAboutPageView();
    MockAboutPageTitleView pageTitleView = new MockAboutPageTitleView();
    MockAboutPageKeywordsView pageKeywordsView = new MockAboutPageKeywordsView();
 
    MockAboutPageContentView pageContentView = new MockAboutPageContentView();
    MockAboutPageContentHtmlView pageContentHtmlView = new MockAboutPageContentHtmlView();
 
    private MockRepository _mocks;
    private AboutPresenter _presenter;
 
    private string pageName;
    private string languageEnUs;
    private string languageDeDe;
    private string sectionMain;
 
    [SetUp]
    public void SetUp()
    {
        TestUtil.SetUpHttpContext();
        _mocks = new MockRepository();
        _presenter = _mocks.Stub<AboutPresenter>();
 
        pageName = MethodType.Page.Company_About.GetStringValue();
        languageEnUs = MethodType.Language.English.GetStringValue();
        languageDeDe = MethodType.Language.German.GetStringValue();
        sectionMain = MethodType.Section.Main.GetStringValue();
    }
 
    [Test]
    public void Company_About_Page_Record_Exists_In_Database_English()
    {
        _presenter.Init(pageView);
        _presenter.PerformLoad(pageName, languageEnUs, sectionMain);
    }
 
    [Test]
    public void Company_About_Page_Title_Exists_In_Database_English()
    {
        _presenter.Init(pageTitleView);
        _presenter.PerformLoad(pageName, languageEnUs, sectionMain);
    }
 
    [Test]
    public void Company_About_Page_Keywords_Exists_In_Database_English()
    {
        _presenter.Init(pageKeywordsView);
        _presenter.PerformLoad(pageName, languageEnUs, sectionMain);
    }
 
    [Test]
    public void Company_About_PageContent_Record_Exists_In_Database_English()
    {
        _presenter.Init(pageContentView);
        _presenter.PerformLoad(pageName, languageEnUs, sectionMain);
    }
 
    [Test]
    public void Company_About_PageContent_Html_Exists_In_Database_English()
    {
        _presenter.Init(pageContentHtmlView);
        _presenter.PerformLoad(pageName, languageEnUs, sectionMain);
    }
 
    [Test]
    public void Company_About_PageDetails_German_NotNull()
    {
        _presenter.Init(pageView);
        _presenter.PerformLoad(pageName, languageDeDe, sectionMain);
    }
 
    [Test]
    public void Company_About_PageDetails_German_TitleNotEmpty()
    {
        _presenter.Init(pageTitleView);
        _presenter.PerformLoad(pageName, languageDeDe, sectionMain);
    }
 
    [Test]
    public void Company_About_PageDetails_German_KeywordsNotEmpty()
    {
        _presenter.Init(pageKeywordsView);
        _presenter.PerformLoad(pageName, languageDeDe, sectionMain);
    }
 
    [Test]
    public void Company_About_PageContent_German_NotNull()
    {
        _presenter.Init(pageContentView);
        _presenter.PerformLoad(pageName, languageDeDe, sectionMain);
    }
 
    [Test]
    public void Company_About_PageContent_German_HtmlNotEmpty()
    {
        _presenter.Init(pageContentHtmlView);
        _presenter.PerformLoad(pageName, languageDeDe, sectionMain);
    }
}
 
public class MockAboutPageView : IAbout
{
    public void LoadHtml(PageFT pageFt, PageContentFT pageContentFt)
    {
        Assert.IsNotNull(pageFt);
    }
}
 
public class MockAboutPageTitleView : IAbout
{
    public void LoadHtml(PageFT pageFt, PageContentFT pageContentFt)
    {
        Assert.IsNotNull(pageFt.Title);
        Assert.IsNotEmpty(pageFt.Title);
    }
}
 
public class MockAboutPageKeywordsView : IAbout
{
    public void LoadHtml(PageFT pageFt, PageContentFT pageContentFt)
    {
        Assert.IsNotNull(pageFt.Keywords);
        Assert.IsNotEmpty(pageFt.Keywords);
    }
}
 
public class MockAboutPageContentView : IAbout
{
    public void LoadHtml(PageFT pageFt, PageContentFT pageContentFt)
    {
        Assert.IsNotNull(pageContentFt);
    }
}
 
public class MockAboutPageContentHtmlView : IAbout
{
    public void LoadHtml(PageFT pageFt, PageContentFT pageContentFt)
    {
        Assert.IsNotNull(pageContentFt.PageContent);
        Assert.IsNotEmpty(pageContentFt.PageContent);
    }
}

Now we have to setup the configuration file for CruiseControl.NET and add a task in the NAnt build script.

CruiseControl.NET ccnet.config

<project name="Test">
  <labeller type="defaultlabeller" />
  <webURL>http://localhost/ccnet/ViewFarmReport.aspx</webURL>
 
  <sourcecontrol type="filtered">
    <sourceControlProvider type="svn" autoGetSource="true">
      <executable>C:\Program Files\VisualSVN Server\bin\svn.exe</executable>
      <trunkUrl>http://domain.com/svn/ProjectName/trunk</trunkUrl>
      <workingDirectory>D:\Projects\compile\ProjectName\trunk</workingDirectory>
      <tagOnSuccess>false</tagOnSuccess>
      <tagBaseUrl>http://domain.com/svn/ProjectName/tags</tagBaseUrl>
      <username>rmartin</username>
      <password>*******</password>
    </sourceControlProvider>
    <inclusionFilters>
      <pathFilter>
        <pattern>**/*.*</pattern>
      </pathFilter>
    </inclusionFilters>
  </sourcecontrol>
 
  <tasks>
    <msbuild>
      <executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
      <workingDirectory>D:\Projects\compile\ProjectName\trunk\Source</workingDirectory>
      <projectFile>ProjectNameWeb.sln</projectFile >
      <buildArgs>
        /noconlog
        /noconsolelogger /v:quiet
        /p:Configuration=Debug
        /p:ReferencePath="D:\Projects\compile\ProjectName\trunk\Binaries\NUnit"
      </buildArgs>
      <targets>ReBuild</targets >
      <timeout>600</timeout >
      <logger>c:\Program Files\CruiseControl.NET\server\Rodemeyer.MsBuildToCCNet.dll</logger>
    </msbuild>
 
    <nunit>
      <path>D:\Projects\compile\ProjectName\trunk\Binaries\NUnit\nunit-console.exe</path>
      <assemblies>
        <assembly>D:\Projects\compile\ProjectName\trunk\Source\ProjectNameWebTests\bin\Debug\ProjectName.ProjectNameWebTests.dll</assembly>
      </assemblies>
    </nunit>
  </tasks>
 
  <publishers>
    <merge>
      <files>
        <file>C:\Program Files\CruiseControl.NET\server\Test\Artifacts\results.xml</file>
      </files>
    </merge>
    <xmllogger />
    <statistics />
    <email
      from="ProjectNameBuild@domain.com"
      mailhost="mail.domain.com" includeDetails="TRUE">
      <users>
        <user name="Ryan Martin" group="buildmaster" address="rmartin@domain.com"/>
      </users>
      <groups>
        <group name="buildmaster" notification="always"/>
      </groups>
    </email>
  </publishers>
</project>

NAnt build script

<project name="ProjectNameWeb" default="build" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
  <!-- Properties -->
  <property name="devserver.website.dir" value="D:\Projects\www\ProjectName"/>
  <property name="trunk.dir" value="..\" />
  <property name="source.dir" value="${trunk.dir}\Source" />
  <property name="msbuild.exe" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe" />
  <property name="solution.sln" value="${source.dir}\ProjectNameWeb.sln" />
 
  <!-- Called Externally -->
  <target name="build" depends="compile" />
  <target name="test" depends="compile, test.project.ProjectNameWeb" />
 
  <!-- Coding Tasks -->
  <target name="move.assemblies.for.tests" depends="compile">
    <echo message="Moving contents of ${ProjectNameWebTests.bin.dir} to ${assemblies.output.dir}" />
 
    <copy todir="${assemblies.output.dir}" flatten="true">
      <fileset basedir="${ProjectNameWebTests.bin.dir}">
        <include name="*.dll" />
      </fileset>
    </copy>
  </target>
 
  <target name="test.project.ProjectNameWeb" depends="move.assemblies.for.tests">
    <echo message="Starting to run tests for ProjectNameWeb" />
 
    <nunit2 haltonfailure="false" failonerror="false" verbose="true">
      <formatter type="Xml" extension=".xml" outputdir="${nunit.output.dir}" usefile="true" />
      <test assemblyname="${assemblies.output.dir}\ProjectNameWebTests.dll" />
    </nunit2>
  </target>
</project>

Run the task through CruiseControl.NET Web dashboard and viewed the results.

After click on the FORCE button for Test click on the most recent build number

And view the results by clicking the Nunit Details link on the left hand panel

What we make out of this test is the About.aspx page has content for the body, title and keywords in English but that content has either not been translated into German yet or it should be and now we know there is a problem that needs to be addressed

Tags: , , , ,

Dec 15 2009

Integrate FxCop code analysis into CruiseControl.NET

Category: Continuous Integrationryancmartin1976 @ 21:01

First Strategy:

Second Strategy:

Integrating FxCop into CruiseControl.NET

I am not a fan of this technology and I would probably steer away from using this in future projects.

There are three steps in setting up, configuring and viewing the results of FxCop within your Continuous Integration process.

STEP 1

Add a CruiseControl.NET task in your ccnet.config file

<project name="FxCop">
  <labeller type="defaultlabeller" />
  <webURL>http://localhost/ccnet/ViewFarmReport.aspx</webURL>
 
  <sourcecontrol type="filtered">
    <sourceControlProvider type="svn" autoGetSource="true">
      <executable>C:\Program Files\VisualSVN Server\bin\svn.exe</executable>
      <trunkUrl>http://domain.com/svn/ProjectName/trunk</trunkUrl>
      <workingDirectory>D:\Projects\compile\ProjectName\trunk</workingDirectory>
      <tagOnSuccess>false</tagOnSuccess>
      <tagBaseUrl>http://domain.com/svn/ProjectName/tags</tagBaseUrl>
      <username>rmartin</username>
      <password>*******</password>
    </sourceControlProvider>
    <inclusionFilters>
      <pathFilter>
        <pattern>**/*.*</pattern>
      </pathFilter>
    </inclusionFilters>
  </sourcecontrol>
 
  <tasks>
  <exec>
  <executable>C:\Program Files\Microsoft FxCop 1.36\FxCopCmd.exe</executable>
  <baseDirectory>D:\Projects\compile\ProjectName\trunk\source\</baseDirectory>
  <buildArgs>
      /p:"d:\Projects\compile\ProjectName\trunk\Build\rules.FxCop" 
      /out:"c:\Program Files\CruiseControl.NET\server\FxCop\Artifacts\results.xml" /gac
  </buildArgs>
  <buildTimeoutSeconds>300</buildTimeoutSeconds>
  </exec>
  </tasks>
 
  <publishers>
    <merge>
      <files>
        <file>c:\Program Files\CruiseControl.NET\server\FxCop\Artifacts\results.xml</file>
      </files>
    </merge>
    <xmllogger />
    <statistics />
    <email
      from="ProjectNameBuild@domain.com"
      mailhost="mail.domain.com" includeDetails="TRUE">
      <users>
        <user name="Ryan Martin" group="buildmaster" address="rmartin@domain.com"/>
      </users>
      <groups>
        <group name="buildmaster" notification="always"/>
      </groups>
    </email>
  </publishers>
</project>

STEP 2

Add a task in your NAnt build script

<?xml version="1.0" encoding="utf-8"?>
<project name="ProjectNameWeb" default="build" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
  <!-- Properties -->
  <property name="fxcop.output.dir" value="${build.output.dir}\FxCopOutput" />
  <property name="fxcopcmd.exe" value="C:\Program Files\Microsoft FxCop 1.36\fxcopcmd.exe" />
  <property name="rules.fxcop" value="rules.fxcop" />
  <property name="fxcop.xml" value="${fxcop.output.dir}\fxcop.xml" />
 
  <!-- Called Externally -->
  <target name="build" depends="compile" />
  <target name="fxcop" depends="compile, reporting" />
 
  <!-- Coding Tasks -->
  <target name="reporting" depends="compile">
    <exec program="${fxcopcmd.exe}" commandline="/p:${rules.fxcop} /o:${fxcop.xml}" failonerror="false"/>
  </target>
</project>

STEP 3

Go to your CruiseControl.NET Web Dashboard to run and view the results from FxCop

Click the FORCE button for the FxCop task and review the results it generates

NOT WORTH IT IN MY OPINION, RESHARPER DOES A LOT OF THE SAME FUNCTIONALITY IN REAL TIME

Tags: , , , , ,

Dec 15 2009

Deploy Subversion code base into your development environment via CruiseControl.NET

Category: Continuous Integrationryancmartin1976 @ 21:00

First Strategy:

Second Strategy:

Deploy your local code to development for further testing with a click of a button

There are 3 techniques used here to make code deployment seamless for testing in your development environment.

  1. Setup a server to be the development server
  2. Add your project to Subversion
  3. Configure your cruisecontrol.net configuration file and nant build script accordingly

STEP 1

Pick any server to be your development server, potentially one that you use for all projects and sites. This server should mirror your production server, same frameworks, executables and services.

STEP 2

Add your local project to your Subversion server.

STEP 3

Configure the CruiseControl.NET ccnet.config file to call Nant build task without an interval trigger. This assures that the versioned codebase will never get copied over by accident.

<project name="Deploy-To-Development">
  <labeller type="defaultlabeller" />
  <webURL>http://localhost/ccnet/ViewFarmReport.aspx</webURL>
 
  <sourcecontrol type="filtered">
    <sourceControlProvider type="svn" autoGetSource="true">
      <executable>C:\Program Files\VisualSVN Server\bin\svn.exe</executable>
      <trunkUrl>http://domain.com/svn/ProjectName/trunk</trunkUrl>
      <workingDirectory>D:\Projects\compile\ProjectName\trunk</workingDirectory>
      <tagOnSuccess>false</tagOnSuccess>
      <tagBaseUrl>http://domain.com/svn/ProjectName/tags</tagBaseUrl>
      <username>rmartin</username>
      <password>Madison1</password>
    </sourceControlProvider>
    <inclusionFilters>
      <pathFilter>
        <pattern>**/*.*</pattern>
      </pathFilter>
    </inclusionFilters>
  </sourcecontrol>
 
  <tasks>
    <nant>
      <executable>D:\Projects\compile\ProjectName\trunk\binaries\nant\bin\nant.exe</executable>
      <baseDirectory>D:\Projects\compile\ProjectName\trunk\source\</baseDirectory>
      <buildArgs>-D:svn.executable="D:\Projects\compile\ProjectName\trunk\binaries\subversion\svn.exe"</buildArgs>
      <nologo>false</nologo>
      <buildFile>D:\Projects\compile\ProjectName\trunk\Build\ProjectName.build</buildFile>
      <targetList>
        <target>deploy-to-development</target>
      </targetList>
      <buildTimeoutSeconds>1200</buildTimeoutSeconds>
    </nant>
  </tasks>
 
  <publishers>
    <merge>
      <files>
        <file>C:\Program Files\CruiseControl.NET\server\Deploy-To-Development\Artifacts\results.xml</file>
      </files>
    </merge>
    <xmllogger />
    <statistics />
    <email
      from="ProjectNameBuild@domain.com"
      mailhost="mail.domain.com" includeDetails="TRUE">
      <users>
        <user name="Ryan Martin" group="buildmaster" address="rmartin@domain.com"/>
      </users>
      <groups>
        <group name="buildmaster" notification="always"/>
      </groups>
    </email>
  </publishers>
</project>

Next setup the NAnt build script to run a task that does the deployment

<?xml version="1.0" encoding="utf-8"?>
<project name="IpswitchftWeb" default="build" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
  <!-- Properties -->
  <property name="devserver.website.dir" value="D:\Projects\www\ProjectName"/>
  <property name="trunk.dir" value="..\" />
  <property name="source.dir" value="${trunk.dir}\Source" />
  <property name="msbuild.exe" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe" />
  <property name="solution.sln" value="${source.dir}\ProjectNameWeb.sln" />
 
  <!-- Called Externally -->
  <target name="build" depends="compile" />
  <target name="deploy-to-development" depends="compile, deploy.to.development" />
 
  <target name="deploy.to.development">
    <echo message="Deleting all files in development web directory"/>
    <delete verbose="true">
      <fileset basedir="${devserver.website.dir}">
        <include name="*.*" />
      </fileset>
    </delete>
 
    <echo message="XCopy files to development web directory"/>
    <copy todir="${devserver.website.dir}" includeemptydirs="false" overwrite="true">
      <fileset basedir="${ProjectNameWeb.dir}">
        <exclude name="**/obj/**"/>
        <exclude name="**/*.csproj"/>
        <exclude name="**/*.csproj*"/>
        <exclude name="**/App_Data*"/>
        <exclude name="**/App_Data*/**"/>
        <exclude name="**/.svn*"/>
        <exclude name="**/.svn*/**"/>
        <include name="**"/>
      </fileset>
    </copy>
  </target>
</project>

Next run the task from CruiseControl.NET Web Dashboard

This process takes about 30 seconds to 3 minutes depending on the size of the application. You can add all types of files to exclude from the copy over which saves you tons of time in it from doing it manually. This is especially helpful when your project is in Subversion and you have all of those .svn folders everywhere.

Tags: , , ,

Dec 15 2009

Report on your code base for TODO comments via CruiseControl.NET

Category: Continuous Integrationryancmartin1976 @ 20:59

First Strategy:

  • a
  • b
  • c

Second Strategy:

Everyone has to do's in their code comments, so here is an easy way to to check how many you have left in your project

STEP 1

Add a new project to your solution called BuildTasks. Add a new class called ParseCodeDebt.cs

Here is the class code

using System.Diagnostics;
using System.IO;
using NAnt.Core;
using NAnt.Core.Attributes;
 
[TaskName("ParseCodeDebt")]
public class ParseCodeDebt : Task
{
    private string CurrentFolder { get; set; }
 
    public void PerformTest()
    {
        ExecuteTask();    
    }
 
    [TaskAttribute("PathToParse", Required = true)]
    [StringValidator (AllowEmpty = false)]
    public string PathToParse { get; set; }
    protected override void ExecuteTask()
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();
        Log(Level.Warning,"---------------------------------------------------------------------------");
        Log(Level.Warning, "CODE DEBT CHECK for " + PathToParse);
 
        //iterate through all the files in a directory recursively
        System.IO.DirectoryInfo root = new DirectoryInfo(PathToParse);
        WalkDirectoryTree(root);
 
        Log(Level.Warning, "");
        Log(Level.Warning, "Completed in " + sw.ElapsedMilliseconds + "ms");
        Log(Level.Warning, "---------------------------------------------------------------------------");
        Log(Level.Warning, "");
    }
 
    private void WalkDirectoryTree(System.IO.DirectoryInfo root)
    {
        System.IO.FileInfo[] files = null;
        System.IO.DirectoryInfo[] subDirs = null;
 
        // First, process all the files directly under this folder
        try
        {
            files = root.GetFiles("*.*");
        }
            // This is thrown if even one of the files requires permissions greater
            // than the application provides.
        catch (UnauthorizedAccessException e)
        {
            // This code just writes out the message and continues to recurse.
            Log(Level.Warning, e.Message);
        }
 
        catch (System.IO.DirectoryNotFoundException e)
        {
            Log(Level.Warning, e.Message);
        }
 
        if (files != null)
        {
            foreach (System.IO.FileInfo fi in files)
            {
                if (fi.Name.ToLower().EndsWith(".cs") && fi.Name.ToLower() != "parsecodedebt.cs")
                {
                    try
                    {
                        //look for code debt in this file
                        ParseFile(fi);
                    }
                    catch (FileNotFoundException e)
                    {
                        Log(Level.Warning, e.Message);
                    }
                }
            }
 
            // Now find all the subdirectories under this directory.
            subDirs = root.GetDirectories();
 
            foreach (System.IO.DirectoryInfo dirInfo in subDirs)
            {
                if (dirInfo.Name != ".svn")
                {
                    // Resursive call for each subdirectory.
                    WalkDirectoryTree(dirInfo);
                }
            }
        }
    }
 
    private void ParseFile(FileInfo file)
    {
        StreamReader sr = file.OpenText();
        int lineNumber = 1;
        string line = "";
        line = sr.ReadLine();
        while(line!=null)
        {
            if(line.ToLower().Contains("//codedebt"))
            {
                if (CurrentFolder != file.DirectoryName)
                {
                    CurrentFolder = file.DirectoryName;
                    Log(Level.Warning, "");
                    Log(Level.Warning, CurrentFolder);
                }
                Log(Level.Warning, "\t" + file.Name);
                string[] attributes = line.ToLower().Replace("//codedebt","").Trim().Split('|');
                Log(Level.Warning, "\tLine " + lineNumber.ToString());
                foreach (string s in attributes)
                {
                    Log(Level.Warning, "\t" + s.Trim());
                }
            }
            lineNumber++;
            line = sr.ReadLine();
        }
        sr.Close();
    }
}

STEP 2

Next you need to create a new NAnt build task, here is the code

<?xml version="1.0" encoding="utf-8"?>
<project name="ProjectNameWeb" default="build" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
  <!-- Properties -->
  <property name="trunk.dir" value="..\" />
  <property name="dependencies.dir" value="${trunk.dir}\dependencies" />
 
  <!-- Custom Assemblies -->
  <loadtasks assembly="${dependencies.dir}\CustomBuildTasks\CustomBuildTasks.dll"/>
  <loadtasks assembly="${dependencies.dir}\NCover\NCover.NAntTasks.dll"/>
  <loadtasks assembly="${dependencies.dir}\NCover\NCoverExplorer.NAntTasks.dll"/>
 
  <!-- Called Externally -->
  <target name="findToDo" depends="compile, parseCodeDebt" />
 
  <!-- Coding Tasks -->
  <target name="parseCodeDebt">
  <ParseCodeDebt RootPathToParse="${ProjectNameWeb.dir}" 
    DirectoriesToIgnore=".svn,_ReSharper.ProjectNameWeb" 
    FileTypeToProcess=".cs" />
  <ParseCodeDebt RootPathToParse="${ProjectNameWebTests.dir}" 
    DirectoriesToIgnore=".svn,_ReSharper.ProjectNameWeb" 
    FileTypeToProcess=".cs" />
  </target>
</project>

STEP 3

Go to your log4net output directory and open up the file and your Custom NAnt Build task should of dumped all of the data there

some more text here

Tags: , , , ,

Dec 15 2009

Compile your solution with and without MSBuild via CruiseControl.NET

Category: Continuous Integrationryancmartin1976 @ 20:57

First Strategy:

Second Strategy:

Compiling your solution every time subversion has a new commit

There are 2 ways to compile a solution in CruiseControl.NET, with MSBuild and without. I use both, one, without, is very simple process and runs every time a new file is committed to Subversion.

Compiling without MSBuild in ccnet.config

<project name="Build">
  <labeller type="defaultlabeller" />
  <webURL>http://localhost/ccnet/ViewFarmReport.aspx</webURL>
 
  <sourcecontrol type="filtered">
    <sourceControlProvider type="svn" autoGetSource="true">
      <executable>C:\Program Files\VisualSVN Server\bin\svn.exe</executable>
      <trunkUrl>http://domain.com/svn/ProjectName/trunk</trunkUrl>
      <workingDirectory>D:\Projects\compile\ProjectName\trunk</workingDirectory>
      <tagOnSuccess>false</tagOnSuccess>
      <tagBaseUrl>http://domain.com/svn/ProjectName/tags</tagBaseUrl>
      <username>rmartin</username>
      <password>********</password>
    </sourceControlProvider>
    <inclusionFilters>
      <pathFilter>
        <pattern>**/*.*</pattern>
      </pathFilter>
    </inclusionFilters>
  </sourcecontrol>
 
  <triggers>
    <intervalTrigger name="continuous" seconds="120" buildCondition="IfModificationExists" />
  </triggers>
 
  <publishers>
    <merge>
      <files>
        <file>C:\Program Files\CruiseControl.NET\server\Build\Artifacts\results.xml</file>
      </files>
    </merge>
    <xmllogger />
    <statistics />
    <email
      from="ProjectNameBuild@domain.com"
      mailhost="mail.domain.com" includeDetails="TRUE">
      <users>
        <user name="Ryan Martin" group="buildmaster" address="rmartin@domain.com"/>
        <user name="Some Guy" group="buildmaster" address="sguy@domain.com"/>
      </users>
      <groups>
        <group name="buildmaster" notification="always"/>
      </groups>
    </email>
  </publishers>
</project>

Compiling with MSBuild in my nant build script

<?xml version="1.0" encoding="utf-8"?>
<project name="ProjectNameWeb" default="build" xmlns="http://nant.sf.net/release/0.85/nant.xsd">
  <!-- Properties -->
  <property name="devserver.website.dir" value="D:\Projects\www\ProjectName"/>
  <property name="trunk.dir" value="..\" />
  <property name="source.dir" value="${trunk.dir}\Source" />
  <property name="msbuild.exe" value="C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe" />
  <property name="solution.sln" value="${source.dir}\ProjectNameWeb.sln" />
 
  <!-- Called Externally -->
  <target name="build" depends="compile" />
 
  <!-- Coding Tasks -->
  <target name="compile">
    <exec program="${msbuild.exe}" commandline="${solution.sln} /t:Rebuild /v:q" />
  </target>
</project>

Seeing the results

Launch the CruiseControl.NET from Programs -> CruiseControl.NET -> CruiseControl.NET from the server where you installed CruiseControl.NET. The software will run the tasks in the configuration file you setup in ccnet.config

I recommend using the windows service which runs continuously and does all of the automation for you based off of the interval trigger you setup in the file as well. The interval triggers are task specific.

And lastly you can force builds and view the result in the CruiseControl.NET Web dashboard.

Tags: , , , ,