When you use Maven to develop a Jenkins plugin, Maven does most of this using hpi
.
A plugin is really just a jar file that follows a certain set of conventions, as described below:
foo.hpi +- META-INF | +- MANIFEST.MF +- WEB-INF | +- classes | +- lib +- (static resources)
- A plugin needs to have
an .hpi
extension. The file name body ("foo" portion) of the file name is used as the "short name" of a plugin, and it uniquely distingusihes a plugin. - As you can see, the structure is similar to a WAR file, but there's no
web.xml
. MANIFEST.MF
needs to contain a few additional entries. More on this later.WEB-INF/classes
can have class files that constitute plugins, Jelly view files, and Jelly tag libraries based on tag files. Alternatively, some or all of them can be packaged into a jar and placed intoWEB-INF/lib
.WEB-INF/lib
can have *.jar files, and those are loaded and made available to a pluginClassLoader
, along with the contents ofWEB-INF/classes
.- Static resources, such as images, HTML files, CSS stylesheets, JavaScript files, etc, can be placed at the top of an
.hpi
file (just like a WAR file, again.)
Use the hpi:create
target to create this structure. Use hpi:hpi
to create the .hpi
file.
Manifest
META-INF/MANIFEST.MF
can have all the normal entries, but it needs to contain two more entries for Jenkins in its main section.
Plugin-Class
This attribute must have the fully qualified class name of the class that derives from Plugin. Jenkins instantiates this instance to activate a plugin, and everything starts from there. Consequently, a plugin must have one Plugin-derived class. This is the Jenkins plugin version of the Main-Class attribute.
Long-Name
This optional attribute can have a human-readable one line description of the plugin. This is used as "the name" for users (whereas the short name is used as the name internally in Jenkins.) When this attribute is not present, the short name is used as the long name.
Plugin-Dependencies
This optional attribute can have a list of comma-separated plugin short names/versions that are required for this plugin to run. The classes and libraries of those plugins are made visible to this plugin's classloader, so that your plugin can rely on them.
This mechanism allows a plugin to define its own extensibility point, and have other plugins provide implemenations.
Plugin-Dependencies: module-name:version,module2-name:version
Classloader
Per default Jenkins loads every jar from WEB-INF/lib
, along with the contents of WEB-INF/classes
after the classes and libraries of the core. If you want to have your own libaries loaded before these (e.g. you want a newer version of velocity or an other library), you can configure your plugin to use a different classloader strategy by telling the hpi plugin in your pom.xml:
<build> <plugins> <plugin> <groupId>org.jenkins-ci.tools</groupId> <artifactId>maven-hpi-plugin</artifactId> <configuration> <pluginFirstClassLoader>true</pluginFirstClassLoader> </configuration> </plugin> </plugins> </build>
Static Resources
Static resources inside an .hpi
file will be made accessible at ${JENKINS_CONTEXT_PATH}/plugin/SHORTNAME/
. For example, if you have abc/def.png
in foo.hpi
, and if Jenkins is deployed on http://localhost/jenkins/
, then the URL http://localhost/jenkins/plugin/foo/abc/def.png
would display the PNG file.
Index.jelly for Your Plugin
-derived Class
Your Plugin
class (that you named in Plugin-Class
manifest entry) should have index.jelly
view file, which should render 1-2 paragraph worth of the detailed description of your plugin, perhaps with version numbers, link to the homepage, etc. This jelly script will be used in the plugin configuration page so that the user can learn more about a plugin.
Testing With Jenkins
You can test your plugin with a Jenkins instance to use it as a user would. You can also do this with the debugger using mvnDebug
.
Debug Plugin Layout: .hpl
The .hpi
format is primarily meant to be a distribution format. Just like no one debugs the web application by creating a war and deploying it, Jenkins provides another plugin layout called .hpl
(for "Hudson plugin link"), which is targeted for plugin developers to improve productivity.
You can create and install the .hpl
file into a Jenkins installation using mvn hpi:hpl -DhudsonHome=/path/to/jenkinsInstall
The hpl file can be placed in $JENKINS_HOME/plugins
just like hpi files. But hpl file just contains a single line of text that points to a manifest file, like this:../path/to/your/plugin/workspace/manifest-debug.mf The file pointed by this is a manifest file. It has the same custom attributes as defined above for META-INF/MANIFEST.MF
, but it defines a few more custom attributes that allow a plugin developer to specify various pieces of a plugin in different locations in a file system.
Plugin-Class: hudson.plugins.jwsdp_sqe.PluginImpl Class-Path: ./build/classes ./views ./lib/reporter.jar Long-Name: JWSDP SQE Test Result Plugin Resource-Path" ./resources
For example, the above sample manifest-debug.mf
states that the static resources of a plugin shall be loaded from the ./resources
, and class files from ./build/classes
, Jelly view files in ./views
, and a library jar file reporter.jar
shall be made available to the plugin classloader. Absolute path names can be also used.
This mechanism allows a plugin developer to avoid assembly steps. Also, changes to static resources and Jelly views will be reflected instanteneously (provided that you set the system property stapler.jelly.noCache
to true when you start the web container.
Starting Jenkins with your Plugin
You can test your plugin by starting Jenkins using mvn hpi:run -DhudsonHome=/path/to/jenkinsInstall
. You can do this with a copy of the Jenkins code that you have checked out if you wish to debug using the source. The jenkinsInstall
path is the jenkins
directory that you checked out.