Implementing My First Jenkins Plugin: AnsiColor
The Jenkins plugin tutorial is quite good, I recommend you just follow it. It has a maven-based cookbook to generate a new project. But if you’re like me, you’ll reconstruct a plugin from scratch (and possibly trade time for a better understanding). I’ll just mention a few things that could have been helpful to me.
A plugin extends hudson.Plugin. This class isn’t even necessary, but it’s a good opportunity to setup a logger that’s going to tell us that the plugin is actually being loaded. Whether you’re testing the plugin locally or running a production instance of Jenkins, this will come handy.
Processing Build Output
Our goal is to process build output and insert HTML color markup. So the first task is to find a Jenkins extension point from here that exposes build log data. I found the very promising ConsoleLogFilter. A simple extension is marked with @Extension and I thought I was done.
What’s that AnsiColorizer? It’s a stream processing class that inherits from hudson.console.LineTransformationOutputStream that overrides a method called eol, called for each output line. It decorates our logger. Notice that the bytes passed into the eol method are pre-allocated, hence the len parameter. You get a lot more bytes than in the current line, but it’s garbage from previous output after len.
The following code will strip all ANSI markup.
Pretty simple, right? Well, it only works if we want to remove stuff or add text and doesn’t work for HTML. Console output gets HTML-encoded as it passed through subsequent filtering, so inserting HTML, such as color, will end up encoded too. Sad face.
Jenkins has another extension point, BuildWrapper. It will add an option to every build project to enable the decoration of the build logger to which we can attach a ConsoleAnnotationDescriptor. All this is rather convoluted, but constructed with good intentions of being able to stream data. As a recent Rubyist I raised all of my eyebrows time-and-again – I forgot how much people love factories in Java. Anyway, that lets you insert ConsoleNote elements before and after a line of log output. The note is HTML. But ANSI characters can be anywhere in the string, so how is this helpful?
Lets use the extra brain cells that didn’t die while sorting out wrappers, factories, decorators and annotators. Given a string, such as “Hello ]32mCruel Java World”, how do we make it display “Hello <span style=”color: green”>Cruel Java World</span>” given that we can only prepend and append text? Like this.
I know, it’s a total hack, but it works and nobody will complain.
Full plugin source code is here on Github.