Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Minor spelling/grammar

This document, together with the hello-world plugin, shows you how to get started with the plugin development.

Important!

Please first read the "before writing a plugin" page.

There are a lot of existing Jenkins plugins and a lot of people with Jenkins plugin development experience that you can take advantage of!

Check whether there is an existing plugin you can already use, or contribute to, then get in touch via the jenkinsci-dev mailing list, or IRC and explain your plugin idea.
Either we can point you towards an existing plugin, useful APIs, or code snippets that would be helpful.

Table of Contents

Table of Contents
styledisc

What Can Plugins Do?

Jenkins defines extensibility points, which are interfaces or abstract classes that model an aspect of a build system. Those interfaces define contracts of what need needs to be implemented, and Jenkins allows plugins to contribute those implementations. See this document for more about extension points.

...

To develop a plugin, you need Maven 3 (why?) and JDK 6.0 or later. If this is the first time you use are using Maven, make sure Maven can download stuff over the internet.

...

It may be helpful to add the following to your ~/.m2/settings.xml (Windows users will find them in %USERPROFILE%\.m2\settings.xml):

Code Block
xml
xml

<settings>
  <pluginGroups>
    <pluginGroup>org.jenkins-ci.tools</pluginGroup>
  </pluginGroups>

  <profiles>
    <!-- Give access to Jenkins plugins -->
    <profile>
      <id>jenkins</id>
      <activation>
        <activeByDefault>true</activeByDefault> <!-- change this to false, if you don't like to have it on per default -->
      </activation>
      <repositories>
        <repository>
          <id>repo.jenkins-ci.org</id>
          <url>http<url>https://repo.jenkins-ci.org/public/</url>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>repo.jenkins-ci.org</id>
          <url>http<url>https://repo.jenkins-ci.org/public/</url>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>
  <mirrors>
    <mirror>
      <id>repo.jenkins-ci.org</id>
      <url>http<url>https://repo.jenkins-ci.org/public/</url>
      <mirrorOf>m.g.o-public</mirrorOf>
    </mirror>
  </mirrors>
</settings>

...

Creating a New Plugin

To start developing a new Jenkins plugin, use the online skeleton generator, or use an IDE (below).
Alternatively, or if you are more comfortable with Maven, run the following command:

No Format
$ mvn -U orgarchetype:generate -Dfilter=io.jenkins-ci.toolsarchetypes:mavenempty-hpi-plugin:create
plugin
Info

To create a plugin skeleton for Blue Ocean, please see the generator-blueocean-usain Yeoman generator.

This will ask you a few questions, like the groupId (the Maven jargon for the package name) and the artifactId (the Maven jargon for your project name), then create a skeleton plugin from which you can start with.

Make sure you can build this:

No Format
$ cd newly-created-directory
$ mvn package

Explanations:

-U means that Maven should update all relevant Maven plugins (check for plugin updates)
hpi: this prefix specifies that the Jenkins HPI Plugin is being invoked, a plugin that supports development of Jenkins plugins
create is the goal which creates the directory layout and the POM for your new Jenkins plugin and it adds it to the module list
package is a standard phase which compiles all sources, runs the tests and creates a package - when used by the HPI plugin it will create an *.hpi file

Building a Plugin

To build a plugin, run mvn install. This will create the file ./target/pluginname.hpi that you can deploy to Jenkins.

...

You are advised to use the NetBeans plugin for Jenkins/Stapler development. This offers many Jenkins-specific features. Most visibly, create a new plugin using New Project » Maven » Jenkins Plugin, and use Run Projectproject to test it.

IntelliJ IDEA

IntelliJ 7.0 (or later) users can load pom.xml directly from IDE, and you should see all the source code of libraries and Jenkins core all the way to the bottom. Consider installing the IntelliJ IDEA plugin for Stapler to make the development easier.

Alternatively,emtpy create a new Maven project using Create from archetype and Add an Archetype. Select the GroupId and ArtifactId as above and choose RELEASE as version. In the next screen select io.jenkins.plugins as groupID and choose an artifactId (Project name) and Version to your liking. This will automatically create a maven project based on the specified artifact (e.g. empty-plugin).

Info

IntelliJ defaults to downloading sources and JavaDocs on demand. So, to see the source, you may need to click the Download artifacts button in the Maven Projects tab.

...

Use Eclipse Juno (4.2) or later for the best experience.

Note

Eclipse versions between 4.5 and < 4.6.2 contain a bug that causes errors such as "Only a type can be imported. hudson.model.Job resolves to a package".
If you encounter this error please upgrade to Eclipse Neon.2 (4.6.2) or higher (Bug 495598).

As Jenkins plugins are Maven projects, Eclipse users have two ways to load a Jenkins plugin project. One is to use m2e, which tries to make Eclipse understand Maven "natively", and the other is to use theusing maven, but Maven Eclipse plugin, which makes Maven generate Eclipse project definitions. At the moment, unless you have some prior experience with m2e, we currently recommend plugin developers to go with the Maven Eclipse plugin.

...

No Format
$ mvn -DdownloadSources=true -DdownloadJavadocs=true -DoutputDirectory=target/eclipse-classes -Declipse.workspace=/path/to/workspace eclipse:eclipse eclipse:configure-workspace

Where /path/to/workspace is the path to your Eclipse workspace.

Once this command completes successfully, use "Import..." (under the File menu in Eclipse) and select "General" > "Existing Projects into Workspace".

...

See Jenkins plugin development with Eclipse for gotchas and other known Eclipse/Maven related issues with Jenkins plugin development.

See Eclipse alternative build setup for an alternative way of setting up the Eclipse build environment, that is a bit more technically involved than using Maven but can give faster build times.

Plugin Workspace Layout

The plugin workspace consists of the following major pieces, described in additional detail at Plugin Structure:

pom.xml

Maven uses it for building your plugin.the pom.xml file to build your Jenkins plugin. All Jenkins plugins should be based on the Plugin Parent POM:

Code Block
xml
xml
<parent>
    <groupId>org.jenkins-ci.plugins</groupId>
    <artifactId>plugin</artifactId>
    <version>2.2</version>
</parent>

If the project is created using the provided archetype, everything is already set up. Up to Jenkins 1.645 the Plugin Parent POM was part of the main Jenkins project and the POM version was the baseline Jenkins version to be used for the plugin.

When using Parent POM version 2.2 or later, the baseline version is selection using the jenkins.version property, e.g.:

Code Block
xml
xml
<properties>
    <jenkins.version>1.609.1</jenkins.version>
</properties>

src/main/java

Java source files of the plugin.

...

Static resources of the plugin, such as images and HTML files.

Source Code

...

PluginImpl approach

(deprecated in favor of the Extension points approach below)

A plugin's main entry point is may be a PluginImpl class that extends from Plugin. Once Jenkins detects your this plugin class (via its inheritance relationship from Plugin), it will create an instance, and invoke methods.

Extension points approach

A Plugin class is optional; a plugin may simply implement extensions:Most of the time, a plugin class just registers extension points, and your main work involves extension points, registering them with the @hudson.Extension annotation for automatic detection by Jenkins.

The bulk of work in the plugin consists of implementing those extension points. See the sample source code for more information about how a Builder is implemented and what it does.

Here are a few things about extension:

  • in general, a plugin extension should extend an existing extension point (a class that implements ExtensionPoint), and define an inner static class extending the corresponding descriptor (a class extending hudson.model.Descriptor)
  • the @Extension annotation must be placed on the inner descriptor class to let Jenkins know about this extension
  • the descriptor handles the global configuration of the extension while the extension class itself handles the individual configuration of the extension. For instance, the Setting context path
    in a plugin defining a class extending LabelAtomProperty, an object of this class is instantiated for each LabelAtom (provided that the plugin is activated by the user in the label's configuration page). If configuration parameters for each individual instance are required, they're handled via a config.jelly file stored in a resource package named after the extension class. When the configuration form is saved, Jenkins calls the extension constructor marked with the @org.kohsuke.stapler.DataBoundConstructor annotation, matching parameters by name

Debugging a Plugin

NetBeans 6.7+ users can just hit Debug. For all others, run the following command to launch Jenkins with your plugin:
Convenient:

...

No Format
> set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=8000,suspend=n
> mvn hpi:run

If you open http://localhost:8080/jenkins in your browser, you should see the Jenkins page running in Jetty. The MAVEN_OPTS portion launches this whole thing with the debugger port 8000, so you should be able to start a debug session to this port from your IDE.

...

  1. When you make changes to view files in src/main/resources or resource files in src/main/webapp, just hit F5 in your browser to see the changes.
  2. When you change Java source files, compile them in your IDE (NetBeans 6.7+: Debug > Apply Code Changes) and Jetty should automatically redeploy Jenkins to pick up those changes. There is no need to run mvn at all.

    Info

    MAVEN_OPTS can be used to specify all sorts of other JVM parameters, like -Xmx

...

maven-hpi-plugin 1.65 or later (used by parent POM 1.401 or later) can set the context path by using a system property. On more recent versions of Jenkins, the "/jenkins" prefix is added automatically.

No Format
$ mvn hpi:run -Dhpi.prefix=/jenkins

Changing code while debugging

Depending on what you change, you can see it in the running instance without restarting the whole Maven process:

  • Views: Groovy/Jelly views are re-compiled every time a browser requests a page, so just reload a page in the browser and you'll see the changes. This is also true for help files you write.
  • Java code: If you are debugging, JVM's hot swap feature can be used to reload code so long as you do not touch the method signature. (For example, from NetBeans use Debug » Apply Code Changes.) Beyond that, you can hit ENTER in the Maven process and it'll reload the Jenkins webapp, though generally, it is better to stop the process and start again. See Developing with JRebel for how to get a JRebel license for OSS projects to improve this experience.
  • POM: If you change POM, you'll have to stop and restart Maven to see the changes.

If you are using version 1.120 or later of maven-hpi-plugin, which would be the default when using version 2.16 or later of the plugin parent POM, you can use the same features to debug changes spanning multiple plugins, or even a custom build of Jenkins core. Just make sure you have SNAPSHOT dependencies set up between the associated Maven modules (<scope>test</scope> suffices), and that the upstream module(s) have been built (e.g., mvn -DskipTests clean install). Now hpi:run on the downstream plugin and you should be able to reload views defined in any of the linked modules.

Distributing a Plugin

To create a distribution image of your plugin, run the following Maven command:

...

  1. Consider running Maven like this mvn -o ... to avoid hitting repositories every time. This will make various operations considerably faster.
  2. Subscribe to the users' alias from here so that we can get in touch with you.
  3. When you bump up the version of Jenkins you depend on, make sure to run mvn clean once, in particular, to delete target/work that Jetty uses. Newer versions may just use work, not target/work. Otherwise, your Jetty may continue to pick up old left-over JAR files.
  4. If you have a high latency network connection to the Maven repository, you might find it faster to first run the build once on a server near to the maven repository, then rsync the .m2/repository folder across to your local computer
  5. The 'package' and 'install' targets will by default run many tests. You can add '-DskipTests' on the command-line to skip these (of course you should run the tests before committing any changes)
  6. The 'compiler:compile' goal is faster than 'compile', because it is a goal, rather than a lifecycle event, and therefore avoids certain earlier goals, such as setting up resources

Other resources

Besides this tutorial, there are other tutorials and examples available on lineonline: