Skip to main content
Jump to: navigation, search

Plugin Directory Structure

When you use Maven2 to develop a Hudson plugin, Maven takes care of most of the stuff explained here.

A plugin is really just a jar file that follows a certain set of conventions, as described below:

 |   +- 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 into WEB-INF/lib.
  • WEB-INF/lib can have *.jar files, and those are loaded and made available to a plugin ClassLoader, along with the contents of WEB-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.)


META-INF/MANIFEST.MF can have all the normal entries, but it needs to contain two more entries for Hudson in its main section.


This attribute must have the fully qualified class name of the class that derives from Plugin. Hudson instantiates this instance to activate a plugin, and everything starts from there. Consequently, a plugin must have one Plugin-derived class. This is the Hudson plugin version of the Main-Class attribute.


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 Hudson.) When this attribute is not present, the short name is used as the long name.


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 implementations.

Plugin-Dependencies: module-name:version,module2-name:version

Static Resources

Static resources inside an .hpi file will be made accessible at ${HUDSON_CONTEXT_PATH}/plugin/SHORTNAME/. For example, if you have abc/def.png in foo.hpi, and if Hudson is deployed on http://localhost/hudson/, then the URL http://localhost/hudson/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.

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, Hudson provides another plugin layout called .hpl (for "Hudson plugin link"), which is targeted for plugin developers to improve productivity.

The hpl file can be placed in $HUDSON_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/ 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 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.

Back to the top