Download DOWNLOAD
Forums FORUMS
Blogs BLOGS
Forge FORGE
Help HELP
Marketplace MARKETPLACE
DotNetNuke Home
You are here >   Community > Blogs
Register  |  Login

DNN Blog

Feb 3

Posted by: Jon Henning
2/3/2009 

Last post in this series we learned some basics of MSBuild, including the use of 3rd party tasks.  We saw that by simply importing some other targets file we can extend the functionality available to our scripting language.  The last two pieces to this puzzle happen to be solved by use of 3rd party plugins available on CodePlex:  Deployment and Automating our Build.

Deployment

Every build we wish to publish can easily be published to our project page via the CodePlex MSBuild tasks.  The first step is to import the CodePlex targets file into our script.

<Import Project="$(RootDir)\lib\MSBuildCodePlexTasks\CodePlex.WebServices.Client.Targets" Condition="'$(DeployToCodePlex)' == '1'" />

With our custom tasks imported, creating a new release is as simple as defining a new target and setting a bunch of properties.

<Target Name="DeployToCodePlex" Condition="$(DeployToCodePlex) == '1' and $(ConfigurationName)=='Release'" >
    <CreateRelease
        ProjectName="$(ProjectName)"
        ReleaseName="v$(Major).$(Minor).$(Build).$(Revision) - Nightly"
        IsDefaultRelease="$(IsDefaultRelease)"
        ShowToPublic="$(ShowToPublic)"
        ShowOnHomePage="$(ShowOnHomePage)"
        Description="$(Description)"
        ReleaseDate="$(ReleaseDate)"
        ReleaseStatus="$(ReleaseStatus)"
        Username="$(User)"
        Password="$(Password)" />

Most of the properties mentioned here are pretty self-evident.  What may not be is where they are defined.  The fact that we are publishing our source code to the central server and it is this code that we are using to publish code, it probably is not a good idea to put our username and password directly into this script, or any script that gets uploaded to our source control.  Instead, what I chose to do was create a file outside my folder structure that gets imported when it exists. 

<Import Project="$(RootDir)\..\..\DNNWCNonDist.Targets" Condition="Exists('$(RootDir)\..\..\DNNWCNonDist.Targets')" />

This will allow your users who download your code to still run most of your build tasks, but will not give them rights to create a public release!  The basics of this file are as follows.

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
    <DeployDir>$(RootDir)\deploy</DeployDir>
    <DeployToCodePlex>1</DeployToCodePlex>
    <DeployToWebcontrolsSite>0</DeployToWebcontrolsSite>  
    <DotNetNukeDir>D:\dev\DotNetNuke\Core_Development\DotNetNuke_Cambrian\Website</DotNetNukeDir>
    <WebSiteDir>$(RootDir)\website</WebSiteDir>

    <!-- CodePlex Properties-->
    <IsDefaultRelease>false</IsDefaultRelease>
    <ShowToPublic>false</ShowToPublic>
    <ShowOnHomePage>false</ShowOnHomePage>
    <Description>Nightly Build</Description>
    <ReleaseStatus>Planned</ReleaseStatus>
    <User>******</User>
    <Password>******</Password>
</PropertyGroup>
</Project>

With our release created it is now time to use another task to upload our files.  First we need to define what files to use by creating an ItemGroup.

<ItemGroup>
    <ReleaseFile Include="$(DeployDir)\WebControls.install.v$(Major).$(Minor).$(Build).$(Revision).zip">
        <FileType>RuntimeBinary</FileType>
    </ReleaseFile>
    <ReleaseFile Include="$(DeployDir)\WebControls.source.v$(Major).$(Minor).$(Build).$(Revision).zip">
        <FileType>SourceCode</FileType>
    </ReleaseFile>
</ItemGroup>

We then use the UploadFiles task to cause our files to be uploaded.

<UploadFiles
        ProjectName="$(ProjectName)"
        ReleaseName="v$(Major).$(Minor).$(Build).$(Revision) - Nightly"
        ReleaseFiles="@(ReleaseFile)"
        Username="$(User)"
        Password="$(Password)" />

Triggering an Automated Build

In order to completely automate our process, we need a piece of software to monitor our source code at some defined interval and pull down any changes, then simply initiate our build process.  Since all of our deployment logic is encapsulated in our build script this is probably the easiest portion to configure.  I chose to use CruiseControl.NET running locally to handle my builds mainly due to the fact that CodePlex offers a sourcecontrol block for us found here.  If your new to CruiseControl.NET I suggest digging through their documentation.  Once you have cruise installed simply follow the instructions on the CodePlex page:  Copy 3 dlls into the CruiseControl.NET\Server folder and make sure you have the J# redistributable installed.  Yes, I agree, requiring J# for a .NET plugable architecture like Cruise is a bit odd.  To configure your project simply find the CruiseControl.NET Start menu entry and choose CruiseControl.NET Config to edit the xml file used in setting up your project.

<cruisecontrol>
    <project>
        <name>DotNetNuke_WebControls</name>
        <triggers>
            <intervalTrigger seconds="3000" buildCondition="IfModificationExists"/>
        </triggers>
        <workingDirectory>E:\dev\DotNetNuke\CodePlex\DotNetNuke.WebControls</workingDirectory>
        <sourcecontrol type="codeplex">
            <project>dnnwebcontrols</project>
            <projectPath>/trunk</projectPath>
        </sourcecontrol>
        <tasks>
            <msbuild>
                <executable>C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
                <workingDirectory>E:\dev\DotNetNuke\CodePlex\DotNetNuke.WebControls\</workingDirectory>
                <projectFile>DotNetNuke.WebControls.sln</projectFile>
                <buildArgs>/noconsolelogger /p:Configuration=Release /v:diag</buildArgs>
                <targets>Build</targets>
                <timeout>3000</timeout>
                <logger>C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
            </msbuild>
        </tasks>
    </project>
</cruisecontrol>

With cruise you simply define an interval trigger to pull your sourcecode directory.  I chose to only perform a build if a modification has taken place, which I believe is the default.  The interaction with CodePlex is all handled by their plugin, simply specify the project name and path within the source control tree to pull and then launch a msbuild task passing in your solution file.  You will notice that there is no secure information here.  Instead it will be assumed that the DNNWCNonDist.Targets file, mentioned earlier, will be relatively located to the working directory.  Without this file our builds will still work, they just won't be published. 

Closing Thoughts

Obviously I could have spent a lot of time going into each of the details on how to customize your own build environment.  I purposefully chose to address this series at a higher level, to try and give you a roadmap of where to start and what are the pieces you need to consider.  Hopefully you found it helpful.

Tags:

1 comment(s) so far...

Re: Getting Continuous Integration Working With CodePlex: Part III

jon, thanks for the great series of posts -i'll be setting up my own codeplex project soon and this will save me tons of time.

By cathal connolly on   2/4/2009

Networks

Follow DNNCorp on Twitter

LinkedIn

Follow us on Twitter @DNNCorp or join the DotNetNuke Community on LinkedIn

Sponsors

DotNetNuke®, DNN®, and the DotNetNuke logo are trademarks of DotNetNuke Corporation

Hosted by MaximumASP