How to Create a Jenkins Plugin

Jenkins is one of the well-known open source automation servers out there. It allows you to build, deploy and automat your project. It is extensible, meaning you can write your own plugin for your special use case. However, the lack of documentation and working examples makes it suprisingly difficult to build your own plugin. I went through this tidious process myself. This step-by-step guide helps you in building your own Jenkins plugin.

Custom Jenkins Build Step Plugin

Before you start implementing your plugin for Jenkins, have a look at the Jenkins Plugin Repository. For the most common scenarios, there is good chance that you find one that suites your task.

I wanted to write my own buildstep plugin for setting up project environments. This task can be a lengthy process. You have to download the necessary tools, set up the environment, and configure everything correctly.

Build Step Workflow

The goal for this plugin was that these technical challenges should be automated as much as possible. The plugin helps project managers and users to easily add a build step to their Jenkins pipeline which builds a software hosted in a Git repository.

The process is automatic. The necessary tools and configuration is stored in Artifactory and a database. Everything is set up automatically, the project is built, and finally the artifact (for example the installer) is created and stored.

The workflow for the user is as follows.

The user sets up a Jenkins pipeline as he wishes. Then, he can add this plugin as a buildstep which is executed when the pipeline is run. In the plugins configuration view, a backend instance (production, develop, or test) has to be chosen first.

Second, a dropdown is populated with projects on this instance from which one can be selected. Third, another dropdown is filled with the available revisions.

Finally, the selected options are stored and used when the plugin is executed.

What You’ll Learn

  • Setting up a plugin development environment
  • Debugging and running your plugin locally
  • Modifying Jenkins UI components using Jelly
  • Connecting UI and backend
  • Deploying the plugin on Jenkins

Environment Setup

  • Netbeans (v8.2) (You can also use IntelliJ or Eclipse)
  • Maven (v3.5)
  • Java (v8)
  • Netbeans plugins:
    • Hudson UI
    • Hudson
    • Jenkins Plugin Support

Don’t forget to set the system environment variables JAVA_HOME for Java and MAVEN_HOME Maven.

Project setup with Netbeans and Maven

Open Netbeans and install the above mentioned plugins.

Afterwards, create a new project (File -> New Project).

Select Jenkins Plugin under the category Maven. Set your project name and group id to whatever you want and click finish.

The project structure looks like this

  • pom.xml
  • src/main/java
  • src/main/resources
  • src/test/java

Jelly UI Components

Jenkins uses Jelly for creating the views.

Jelly is a Java and XML based scripting and processing engine. A Jelly script is an XML document which gets parsed into a script. The tag values are bind to the Java code via reflection techniques.

The following Jelly snippet creates three dropdowns.

Each dropdown is hosted within an f:entry tag. An entry is a form, which is one logical row (that consists of several <TR> tags). Each dropdown has a title which is shown to its left. The field attribute is a unique identifier we use to bind the tags value to our code’s attributes.

The first dropdown has three options and is filled with predefined values. The selected attribute is used to auto-select the option which was selected when we saved the plugin configuration the last time.

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">

    <f:entry title="Portal instance" field="rdInstance">
        <select name="rdInstance">
            <f:option value="test" selected="${instance.rdInstance.equals('test')? 'true':null}">test</f:option>
            <f:option value="dev" selected="${instance.rdInstance.equals('dev')? 'true':null}">dev</f:option>
            <f:option value="prod" selected="${instance.rdInstance.equals('prod')? 'true':null}">prod</f:option>               
        </select>
    </f:entry>

    <f:entry title="Project" field="project">
        <f:select />
    </f:entry>

    <f:entry title="Revision" field="revision">
        <f:select />
    </f:entry>
</j:jelly>

Instance is one of the predefined keywords (objects) we can reference from within a Jelly script.

  • app: instance of Jenkins (or Hudson)
  • instance: object currently being configured within a section of a configure page, such as a BuildStep. Null if this is a newly added instance rather than reconfiguring
  • descriptor: the Descriptor plugin object
  • h: an instance of hudson.Functions, with various useful functions

In this example, I accessed the rdInstance attribute via instance.rdInstance. To define code, I have used the dollar sign and curly-braces, as so ${insert code here}.

Jelly offers a bunch of other tags which you can look up in its taglib reference.

Bind UI to Java properties

To bind the selected dropdown values to our Java class properties, we have to annotate our public constructor with @DataBoundConstructor.

We bind the Java attributes to the Jelly properties by adding them to the constructor and providing a public getter method for each of them (be careful to name them accordingly).

@DataBoundConstructor
public ProjectBuilder(String project, String rdInstance, String revision) {
    this.project = project;
    this.rdInstance = rdInstance;
    this.revision = revision;
}

public final String getProject() {
    return project;
}

public final String getRdInstance() {
    return this.rdInstance;
}

public final String getRevision() {
    return this.revision;
}

The next part goes into more details on working with Jelly and how to react to certain  events and user interactions in the implementation.

References

https://wiki.jenkins.io/display/JENKINS/Basic+guide+to+Jelly+usage+in+Jenkins
https://commons.apache.org/proper/commons-jelly
http://reports.jenkins.io/reports/core-taglib/jelly-taglib-ref.html