# Tuesday, November 30, 2004

We’ve recently switched to the latest version of CruiseControl.NET (0.7) and my favorite new feature is the ability of ccnet to deal with CVS directly.  Previously we had to include code in our NAnt build file to do a CVS update at the beginning of the build, then do the CVS tag (so we can tag all the files with the build version) at the end of the build if it was successful. 

The new ccnet will do the update and the label for us, but…

It only supports one format for the labels, which it to allow you to specify a prefix, like “1.0.” and it will increment a number and append it, so you get “ver-1.0.1”, “ver-1.0.2”, etc.  That number resets to 1 every time you restart the ccnet executable.  Hmmm.  What we wanted was to use our previous scheme, which involved the version number we use for our .NET executables (e.g. 1.0.222.3333).  We used the version task from NAntContrib to create that version number on the formula (x.y.monthday.secondssincemidnight). 

Luckily, ccnet .7 provides an interface for the labeling, so you can write your own scheme.  Ours now looks like this…

    [ReflectorType("ourlabeller")]

    public class OurLabeller : ILabeller

    {

        public OurLabeller()

        {

        }

 

        private string majorMinor = "2.0";

        [ReflectorProperty("majorminor", Required=false)]

        public string MajorMinor

        {

            get

            {

                return majorMinor;

            }

            set

            {

                majorMinor = value;

            }

        }

        #region ILabeller Members

 

        public string Generate(IIntegrationResult previousLabel)

        {

            string ver = string.Format("{0}.{1}.{2}",majorMinor,getMonthDay(),calculateSecondsSinceMidnight());

            return ver.Replace(".","_");//it's a label, so no dots...

        }

 

        #endregion

 

        #region ITask Members

 

        public void Run(IIntegrationResult result)

        {

            result.Label = Generate(result);

        }

 

        #endregion

        private int calculateSecondsSinceMidnight()

        {

            DateTime today = DateTime.Now;

            return (today.Hour * 3600 + today.Minute * 60 + today.Second) / 10;

        }

 

        public int getMonthDay()

        {

            DateTime time = DateTime.Now;

            string timeString = string.Format("{0}{1}",time.Month,time.Day);

            return Convert.ToInt32(timeString);

        }

 

    }

So now ccnet will now use our labeling scheme, as long was we stick our new class in an assembly called ccnet.*.plugin.dll.  The config file bit looks like

  <labeller type="ourlabeller">
    <majorminor>2.0</majorminor>
  </labeller> 

We want the version of the assemblies to match the new generated label, so we need to read it in our NAnt buildfile.  CCNET stuffs the label in a property that gets passed to NAnt called ccnet.label, so we can read that in our NAnt build…

  <if propertyexists="ccnet.label">
   <script language="C#">
    <code><![CDATA[
    public static void ScriptMain(Project project) {
     //Shorten the project string (like 1.3.4.5, to 1.3.4)
     string projectVersion = project.Properties["ccnet.label"];
     project.Properties["project.version"] = projectVersion.Replace("_",".");
    }
   ]]></code>
   </script>
  </if>

Comments are closed.