views:

2240

answers:

5

I have a Nant build script which CruiseControl uses to build a solution on-demand.

However, we only recently got CruiseControl so our official build number is different from what is listed in CruiseControl.

I know CruiseControl injects some properties into build scripts so that I can access the CC build number in the script (CCNetLabel) but how do I pass a value back to CC to use as the build number on the UI screen?

Example, CC says build number 2

nAnt script increments a buildnumber.xml value every build, and the official build number is on 123.

I want the CC UI to show last successful build number: 123, not 2, so how do I pass that value back up?

A: 

Did you try to use some environment variables? I believe CCNet can handle these.

I'll dig a bit on this.

Well I see a solution, quite dirty, but anyhow:

1- Add a defaultlabeller section in your CCNET project definition. It will contains the pattern of the build number you want to display.

2- Within NAnt, have a script to update your configuration file, inserting the build number you want to see.

3- Touch (in the Unix sense) the ccnet.exe.config file so as to make it re-load the projects configuration files.

et voilà.

Vinzz
A: 

We had this problem as well. I ended up writing a special CC labelling plugin.

JesperE
You don't have the code to distribute do you?
Matthew Rathbone
No, but it is really not that difficult. Inherit from net.sourceforge.cruisecontrol.LabelIncrementer, follow the API docs, build your plugin into a jar, add the jar to your CC config.xml.
JesperE
+5  A: 

A custom build labeler is required for this. Perforce is our source control provider and we derive our version number from it. The code is as follows:

/// <summary>
/// Gets the latest change list number from perforce, for ccnet to consume as a build label.
/// </summary>
[ReflectorType( "p4labeller" )]
public class PerforceLabeller : ILabeller
{
    //  perforce executable (optional)
    [ReflectorProperty("executable", Required = false)]
    public string P4Executable = "p4.exe";

    // perforce port (i.e. myserver:1234)
    [ReflectorProperty("port", Required = false)]
    public string P4Port = String.Empty;

    // perforce user
    [ReflectorProperty("user", Required = false)]
    public string P4User = String.Empty;

    //  perforce client
    [ReflectorProperty("client", Required = false)]
    public string P4Client = String.Empty;

    // perforce view (i.e. //Dev/Code1/...)
    [ReflectorProperty("view", Required = false)]
    public string P4View = String.Empty;

    // Returns latest change list
    public string Generate( IIntegrationResult previousLabel )
    {
        return GetLatestChangelist(); 
    }

    // Stores latest change list into a label
    public void Run( IIntegrationResult result )
    {
        result.Label = GetLatestChangelist();
    }

    // Gets the latest change list
    public string GetLatestChangelist()
    {
        // Build the arguments to pass to p4 to get the latest changelist
        string theArgs = "-p " + P4Port + " -u " + P4User + " -c " + P4Client + " changes -m 1 -s submitted " + P4View;
        Log.Info( string.Format( "Getting latest change from Perforce using --> " + theArgs ) );

        // Execute p4
        ProcessResult theProcessResult = new ProcessExecutor().Execute( new ProcessInfo( P4Executable, theArgs ) );

        // Extract the changelist # from the result
        Regex theRegex = new Regex( @"\s[0-9]+\s", RegexOptions.IgnoreCase );
        Match theMatch = theRegex.Match( theProcessResult.StandardOutput );
        return theMatch.Value.Trim();
    }
}

The method, GetLatestChangelist, is where you would probably insert your own logic to talk to your version control system. In Perforce there is the idea of the last changelist which is unique. Our build numbers, and ultimately version numbers are based off of that.

Once you build this (into an assembly dll), you'll have to hook it into ccnet. You can just drop the assembly into the server directory (next to ccnet.exe).

Next you modify your ccnet project file to utilize this labeller. We did this with the default labeller block. Something like the following:

<project>
<labeller type="p4labeller">
    <client>myclient</client>
    <executable>p4.exe</executable>
    <port>myserver:1234</port>
    <user>myuser</user>
    <view>//Code1/...</view>
</labeller>
<!-- Other project configuration to go here -->
</project>

If you're just wanting the build number to show up in ccnet then you're done and don't really need to do anything else. However, you can access the label in your NAnt script if you wish by using the already provided CCNetLabel property.

Hope this helps some. Let me know if you have any questions by posting to the comments.

Scott Saad
To compile this I had to add references to ThoughtWorks.CruiseControl.Core.dll and NetReflector.dll (both in the CruiseControl.Net installation folder and then add the following to import the namespaces:using Exortech.NetReflector;using ThoughtWorks.CruiseControl.Core;
robaker
The other thing I would add is that you make sure your assembly dll is named "ccnet.*.plugin.dll" where * is whatever name you choose for your plug-in.
Ken
A: 

If your build numbers are sequential, you can just hack the cruise control state file to give it the correct build number to start with. Your looking for a file called [projectName].state.

I changed the Label element to the correct number and the LastSuccessfulIntegrationLabel to be the new number.

gbanfill
A: 

However, we only recently got CruiseControl so our official build number is different from what is listed in CruiseControl.

Sort of along the lines of what gbanfill said, you can tell CC what build numbers to start from, but there's no need to hack the .ser file. You can use the JMX interface to set the current build number to get it in sync with your NAnt build number.

You can also set the default label value to to your current build number, delete the .ser file and restart CC.

But maybe the easiest thing is to write the build number into a property file from NAnt and then use the property file label incrementer to read that file. (Be sure to to set setPreBuildIncrementer="true")

Jeffrey Fredrick