Tuesday, June 19, 2007

Last time I had post the all.build script for our buildserver.  Those scripts has some includes to other scritps, which weren't included at that moment.  Finally I have found some time to post the next chapter in which these scripts will be included.  So let's start with the scripts:

Properties.build

In this file, we are going to define all properties which are used by our buildserver.  You can find here properties like the fodler structure, sourcesafe account, tools and more. The parts that need to be changed for your project will be written in red.  Depending on the location of your tools, you also need to change the path of it.

<?xml version="1.0"?>
<project name="Properties" xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd">
<include buildfile="properties.user.build"/>
<!-- ###################################################################################### -->
<!-- Visual Basic Compiler Properties -->
<!-- ###################################################################################### -->
<property name="vbc.optionCompare" value="Binary" />
<property name="vbc.optionExplicit" value="true" />
<property name="vbc.optionStrict" value="true" />
<property name="vbc.define" value="DEBUG=true,DEV=false,TST=false,PRD=false" />
<property name="vbc.defineDEV" value="DEBUG=false,DEV=true,TST=false,PRD=false" />
<property name="vbc.defineTST" value="DEBUG=false,DEV=false,TST=true,PRD=false" />
<property name="vbc.definePRD" value="DEBUG=false,DEV=false,TST=false,PRD=true" />
<property name="vbc.debug" value="true" overwrite="false" />
<!-- ###################################################################################### -->
<!-- Folder Properties -->
<!-- ###################################################################################### -->
<property name="root.dir" value="C:\Buildserver\Projects\<Project name>" overwrite="false"/>
<property name="bin.extern.dir" value="${root.dir}/BinExtern" overwrite="false"/>
<mkdir dir="${bin.extern.dir}" if="${not directory::exists(bin.extern.dir)}"/>
<property name="bin.intern.dir" value="${root.dir}/BinIntern" overwrite="false"/>
<mkdir dir="${bin.intern.dir}" if="${not directory::exists(bin.intern.dir)}"/>
<property name="bin.release.dir" value="${root.dir}/Release" overwrite="false"/>
<!-- ###################################################################################### -->
<!-- SourceSafe Properties -->
<!-- ###################################################################################### -->
<property name="vss.user" value="Cruise" overwrite="false"/>
<property name="vss.password" value="cruise" overwrite="false"/>
<property name="vss.dbpath" value="\\<path to your VSS DB>\srcsafe.ini" overwrite="false"/>
<!-- ###################################################################################### -->
<!-- Tool Properties -->
<!-- ###################################################################################### -->
<!-- ###################################################################################### -->
<!-- Misc Properties -->
<!-- ###################################################################################### -->
<property name="outputType" value="Plain" overwrite="false"/>
<!-- ###################################################################################### -->
<!-- Default BuildType Properties -->
<!-- ###################################################################################### -->
<property name="build.type.deploy" value="false" overwrite="false" />
</project>

In this file we also have an include to the properties.user.build.

Properties.user.build

This file can be used for user depend properties.  In the example case below, we use it for reading the root dir of our project out of the ccnet.config file.

<?xml version="1.0"?>
<project name="Properties" xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd">
<xmlpeek property="root.dir" file="../../server/ccnet.config"
     xpath="/cruisecontrol//project[@name=' <Project name>']/@workingDirectory" />
</project>

Buildscripts.refresh.build

Because we want a fully automated Buildserver, which is independ if a project is changing, we also need an automted master.build generation for each project.  The auto generation is already explained in chapter 6.  Now we are going to integrate this in our full package so the server will do the work for us. As usual the red parts need to be changed for your project.

<?xml version="1.0" encoding="utf-8" ?>
<project name="RefreshBuildScripts" xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd">
<!-- ################################################################################################### -->
<!-- GENERATE A NANT BUILD FILE FOR A SET OF VS.NET PROJECTS -->
<!-- ################################################################################################### -->
<property name="solution.dir" value="${root.dir}/<Project name>.Prototype" />
<property name="solution.vss.dir" value="$/Projects/<Your project folder>/<Project name>.Prototype" />
<property name="script.dir" value="${root.dir}\BuildScripts" />
<property name="script.vss.dir" value="$\BuildScripts" />
<property name="transform.xsl.dir" value="${root.dir}/Tools/BuildScriptGenerator" />
<property name="transform.xsl" value="${transform.xsl.dir}/VSConvert.xsl" />
<target name="RefreshBuildScripts">

<!-- Error Handling -->
<property name="nant.onfailure" value="UndoCheckOutMasterBuild" />

<!-- Projects --> <property name="project.name" value="<Project name>.Prototype.Common" />
<call target="RefreshMasterBuild" />
  <property name="project.name" value="<Project name>.Prototype.DAL.AccessDbProvider" />
  <call target="RefreshMasterBuild" /> <property name="project.name" value="<Project name>.Prototype.DAL" />
  <call target="RefreshMasterBuild" /> <property name="project.name" value="<Project name>.Prototype.BL" />
  <call target="RefreshMasterBuild" />

   <!-- Web Applications -->
   <property name="project.name" value=" <Project name>.Prototype.PL.CreditApplication" />
   <call target="RefreshMasterBuild" />
</target>

<!-- Refresh master.build -->
<target name="RefreshMasterBuild" >
  <call target="UpdateProperties" />
  <!-- <call target="CheckOutMasterBuild" />-->
  <call target="GenerateMasterBuild" />
  <!-- <call target="CheckInMasterBuild" />-->
</target>

<!-- Update Property Values -->
<target name="UpdateProperties" >
  <property name="project.dir" value="${solution.dir}" />
  <property name="project.file" value="${project.dir}\${project.name}\${project.name}.csproj" />
  <property name="project.vss.file" value="${solution.vss.dir}\${project.name}\${project.name}.csproj" />
  <property name="project.vss.script" value="${script.dir}\${project.name}\ master.build" />
  <property name="project.script.dir" value="${script.dir}\${project.name}" />
  <property name="project.script" value="${project.script.dir}\master.build" />
</target>

<!-- Checkout master.build -->
<target name="CheckOutMasterBuild">
   <vsscheckout username="${vss.user}" password="${vss.password}" localpath="${project.script.dir}" recursive="false"
       writable="true" dbpath="${vss.dbpath}" path="${project.vss.script}" />
</target>

<!-- Regenerate master.build -->
<target name="GenerateMasterBuild">
  <delete file="${project.script}" verbose="true" failonerror="false" />
  <style style="${transform.xsl}" in="${project.file}" out="${project.script}" />
  <loadfile file="${project.script}" property="file" />
  <property name="newfile" value="${string::replace(file,'REPLACE_','')}" />
  <echo file="${project.script}" message="${newfile}" append="false" />
</target>

<!-- Checkin master.build -->
<target name="CheckInMasterBuild">
  <vsscheckin username="${vss.user}" password="${vss.password}" localpath="${project.script}" recursive="false"
      dbpath="${vss.dbpath}" path="${project.vss.script}"
      comment="Automatic BuildScript Generator on ${environment::get-machine-name()}" />
</target>
 
<!-- Fail: undo checkout -->
<target name="UndoCheckOutMasterBuild">
  <vssundocheckout username="${vss.user}" password="${vss.password}" recursive="false" dbpath="${vss.dbpath}"
         path="${project.vss.script}" />
</target>
</project>

We have excluded the Checkout/in/undo actions with VSS.  This because we have troubles with VSS when doing those actions.  As soon as we have a solution for it (or if anyone has one post in the comments), we will update this chapter.

Clean.build

For every build we need to clean up the previous generated binairies, configs,... . 

<?xml version="1.0"?>
<project name="Clean" xmlns="http://nant.sf.net/release/0.85-rc3/nant.xsd" default="Clean">
<!-- ###################################################################################### -->
<!-- Cleanup -->
<!-- ###################################################################################### -->
<target name="Clean">
<!-- Previous Assemblies, Confif files etc. -->
   <delete>
     <fileset>
       <include name="${bin.intern.dir}\<Project name>.*" />
     </fileset>
   </delete>
</target>
</project>

Webapplication.install.build

When having a web project in your solution, you also want to build using NAnt.  This is no problem.  But when you unittests included in your build process, you must do a few extra steps so your web project (this could also be a web service) will work.  These steps must be done :

  • Creation of a Virtual Directory
  • Changes to IIS must be done
  • ...

The following script will take care of this problem.  It will delete any existing virtual directory,....  Copy the latest binairies to the web folder and create a new virtual directory.

<?xml version="1.0" encoding="utf-8" ?>
<project name="InstallWebApplications" xmlns=http://nant.sf.net/release/0.85-rc3/nant.xsd
   default="InstallWebServices">
<!-- ###################################################################################### -->
<!-- Web Applications Installation -->
<!-- ###################################################################################### -->
<include buildfile="properties.build" />
<property name="vdir.name" value="Fortisbank.BPCA.Prototype.PL.CreditApplication" />
<property name="vdir.path" value="C:\inetpub\wwwroot\<Project name>.Prototype.PL" />
<property name="vdir.iisserver" value="localhost:80" />
<!-- [host]:[port] -->
<property name="src.ws.dir"
   
value="${root.dir}/<Project name>.Prototype/<Project name>.Prototype.PL" overwrite="false" />
<target name="InstallWebApplications">
  <!-- Remove existing IIS Directory -->
  <deliisdir iisserver="${vdir.iisserver}" vdirname="${vdir.name}" failonerror="false" />

  <!-- Delete old version -->
  <delete>
    <fileset basedir="${vdir.path}">
      <include name="**\*.*" />
    </fileset>
  </delete>

  <!-- Copy Sources -->
  <copy todir="${vdir.path}">
    <fileset basedir="${src.ws.dir}">
      <include name="**.aspx" />
    </fileset>
  </copy>

  <!-- Copy Binaries -->
  <copy todir="${vdir.path}\bin">
    <fileset basedir="${bin.intern.dir}">
      <include name="**.*" />
    </fileset>
  </copy>

  <copy todir="${vdir.path}\bin">
    <fileset basedir="${bin.extern.dir}">
      <include name="**.*" />
    </fileset>
  </copy>

<!-- Install new IIS Directory -->
<mkiisdir iisserver="${vdir.iisserver}" dirpath="${vdir.path}" vdirname="${vdir.name}" />

</target>
</project>

CCnet.config using All.build

Now that we have all our scripts, we just need to integrate the all.build file in our ccnet.config file, so that our buildserver will build all our projects and not only those defined in the ccnet.config file.

<cruisecontrol>
<project name="BPCAPrototype" webURL="http:\\localhost\ccnet"
    workingDirectory="C:\Buildserver\Projects\<Your project folder>">
<sourcecontrol type="vss" autoGetSource="true" applyLabel="false">
  <executable>C:\Program Files\Microsoft Visual SourceSafe\win32\SS.EXE</executable>
  <project>$/<Your VSS project folder>/<Project name>.Prototype</project>
  <username>Cruise</username>
  <password>cruise</password>
  <ssdir>\\<path to your VSS DB>\</ssdir>
  <workingDirectory><Project name>.Prototype</workingDirectory>
  <cleanCopy>true</cleanCopy>
</sourcecontrol>

<triggers>
  <intervalTrigger seconds="28800" buildCondition="IfModificationExists" />
</triggers>

<tasks>
  <nant>
    <executable>Tools\Nant\bin\nant.exe</executable>
    <buildArgs>"-D:outputType=Xml"</buildArgs>
    <nologo>false</nologo>
    <buildFile>BuildScripts\all.build</buildFile>
    <targetList>
      <target>
      </target>
    </targetList>
    <buildTimeoutSeconds>1200</buildTimeoutSeconds>
   </nant>
</tasks>
</project>
</cruisecontrol>

As you can see, we have changed the task node.  In chapter 5 we had defined here de master.build file of one project.  We now have changed this to the all.build script, which will build all our projects.

That was it for this time.  We are going to try to add an example solution to this post.  So check it out later.

Next chapter, we will discuss how you can create NAnt script using VS2005. So stay tuned.


Overview Buildserver chapters on my blog :

Chapter 1 : Introduction
Chapter 2 : CruiseControl.Net
Chapter 3 : Projects
Chapter 4 : Project Structure
Chapter 5 : NAnt and all our buildscripts
Chapter 6 : Buildscript generation Part 1
Chapter 7 : Buildscript generation Part 2

6/19/2007 2:44:51 PM (Romance Standard Time, UTC+01:00)  #     |