How to write a CCNet publisher in C#

Anyone doing development and want to be serious about need a build machine. If you’re not only into being serious but also want some fun, why not try enhance the infrastructure by for instance writing your own CCNet plugins?

After some experimenting it turns out to be really simple. All you need to do is implement the interface ITask. There are however a few more things to keep in mind.

Before I start, let me say that everything I learned about this comes from looking at the source of CruiseControl.Net and also peeking at the Twitter Publisher by Thomas Freudenberg.

Your assembly must have a name on the pattern ccnet.*.plugin.dll. The location of the dll must be the same as the ccnet server directory (typically c:\Program Files\CruiseControl.NET\server). During development, feel free to name that as your output directory.

The namespace and class name are not important. However, you need to add an attribute, ReflectorType, to the class. The constructor takes a string. That string is the node you specify in ccnet.config.

I think it is time for an example.

  1. using ThoughtWorks.CruiseControl.Core;
  2. using System.Windows.Forms;
  3. using Exortech.NetReflector;
  4.  
  5. namespace any.name.isvalid
  6. {
  7.   [ReflectorType("mynewpublisher")]
  8.   public class ClassNameNotImportant : ITask
  9.   {
  10.     public void Run(IIntegrationResult result)
  11.     {
  12.       MessageBox.Show(string.Format("yehaa {0} – {1}", result.ProjectName, result.Status));
  13.     }
  14.   }
  15. }

This can be tested by the following configuration file:

  1. <cruisecontrol xmlns:cb="urn:ccnet.config.builder">
  2.   <project name="MyFirstProject" >
  3.     <publishers>
  4.       <mynewpublisher/>
  5.     </publishers>
  6.   </project>
  7. </cruisecontrol>

When you connect your cctray to the project and force it you’ll get a happy message box. Please refrain from using actual message boxes on your server! This is something you should try at home, not at work :)

There are times when your publisher needs some configuration. This is easily accomplished by more attributes;

  1. [ReflectorProperty("user", Required = true)]
  2. public string User { get; set; }

The config file now looks like

  1. <publishers>
  2.   <mynewpublisher>
  3.     <user>jesper</user>
  4.   </mynewpublisher>
  5. </publishers>

If you specify Required=True you will get a startup failure if the xmlnode is not specified!

Some properties are numbers (he said numbly). Fear not, just adorn the adornment some:

  1. [ReflectorProperty("intvalue", Required = true, InstanceType=typeof(int))]
  2. public int intvalue { get; set; }

There is also the odd chance you need a list of items as a property to your publisher. That’s a tad bit more involved, but here goes. First, the config file we want to specify looks like:

  1. <mynewpublisher>
  2.   <user>jesper</user>
  3.   <intvalue>33</intvalue>
  4.   <recipients>
  5.     <recipient name="jesper"/>
  6.     <recipient name="jonas"/>
  7.   </recipients>
  8. </mynewpublisher>

In other words, a list of recipients that each have a name. First, the property on the publisher-class:

  1. [ReflectorHash("recipients", "name")]
  2. public Hashtable Recipients { get; set; }

To make sure we don’t inadvertently hand out nulls we need to add a constructor as well

  1. public ClassNameNotImportant()
  2. {
  3.   Recipients = new Hashtable();
  4. }

We also need to define the class to hold each item. Luckily it is simple.

  1. [ReflectorType("recipient")]
  2. public class Recipient
  3. {
  4.   [ReflectorProperty("name")]
  5.   public string Name { get; set; }
  6. }

Test it in your Run-method.

  1. public void Run(IIntegrationResult result)
  2. {
  3.   MessageBox.Show(string.Format("Recipients: {0}", Recipients.Count));
  4.   foreach (Recipient r in Recipients.Values)
  5.     MessageBox.Show(r.Name);
  6. }

There are a few more attributes that can be used, but I must admit I haven’t investigated them thoroughly. The NetReflector package is available on sourceforge here.

At any rate, this article should be enough to get you started. I’ll definitely start implementing some of my publisher ideas – the Twitter Publisher is admittedly already done, but it was only number three on my list.

–Jesper Hogstrom

  • Share/Bookmark

Leave a comment

Your comment