+ src
+ main
+ java
+ full.package.name
+- MyClassPublisher.java
+- PluginImpl.java
+ full.package.name
+- config.jelly
+- global.jelly
+- index.jelly
+ webapp
+- help-globalConfig.html
+- help-projectConfig.html
+ src
+ test
+ java
+ resources
+ full.package.namePluginImpl.java
public void start() throws Exception { // plugins normally extend Hudson by providing custom implementations // of ‘extension points’. In this example, we’ll add one builder. // BuildStep.BUILDERS.add(HelloWorldBuilder.DESCRIPTOR); Publisher.PUBLISHERS.add(TSLPublisher.DESCRIPTOR); }
TSLPublisher.java
is a class that extends the Publisher class and it’s main purpose is to perform an action once the build process has been completed successfully. An example of Publishers are report generation tools or email sending. This class should look like this:
public class TSLPublisher extends Publisher { private static final Logger logger = Logger.getLogger(TSLPublisher.class.getName()); private Boolean enable; @DataBoundConstructor public TSLPublisher(Boolean enable) { this.enable = enable; } /** * We’ll use this from the <tt>config.jelly</tt>. */ public Boolean getEnable() { return enable; } public boolean needsToRunAfterFinalized() { return true; } /** * This method should have the logic of the plugin. Access the configuration * and execute the the actions. */ public boolean perform(Build build, Launcher launcher, BuildListener listener) { logger.info(”Performing update…”); // TODO: WRITE THE LOGIC OF YOUR PLUGIN HERE!!!! return true; } public Descriptor<publisher> getDescriptor() { return DESCRIPTOR; } public Action getProjectAction(AbstractProject< ?, ?> project) { return null; } /** * Descriptor should be singleton. */ public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); /** * Descriptor for {@link TSLPublisher}. Used as a singleton. * The class is marked as public so that it can be accessed from views. * * <p> * See <tt>global.jelly</tt> * for the actual HTML fragment for the configuration screen. */ public static final class DescriptorImpl extends Descriptor<publisher> { /** * To persist global configuration information, * simply store it in a field and call save(). * * <p> * If you don’t want fields to be persisted, use <tt>transient</tt>. */ private String field; protected DescriptorImpl() { super(TSLPublisher.class); load(); } /** * This human readable name is used in the configuration screen. */ public String getDisplayName() { return “This is the TSL Sample Plugin”; } /** * Get the fields from the configuration form and persist them. */ public boolean configure(HttpServletRequest req) throws FormException { uri = req.getParameter(”tsl.field”); save(); logger.fine(”Saved TSL configuration”); return super.configure(req); } /** * Creates a new instance of {@link TSLPublisher} from a submitted form. */ public TSLPublisher newInstance(StaplerRequest req) throws FormException { logger.fine(”New instance for a job”); return new TSLPublisher(req.getParameter(”tsl.enable”)!=null); } public String getField() { return field; } public void setField(String field) { this.field = field; } } } </p></publisher></p></publisher>
- The perform method do the real thing. To get the configuration parameters, use the DESCRIPTOR singleton to access the POJOs.
- The inner class DescriptorImpl extends Descritor<Publisher>. It is instantiated once and accessed by a Singleton.
- The configure() method reads the parameters and persists them.
- The newInstance() should return an instance of the TSLPublisher to perform the action. I have implemented an enable check. When not enabled, there is no instance for this job.
- All the fields can persist by default. Use transient if you don’t want to persist.
global.jelly
is a file generated automatically by Maven, and it’s the Jelly Script file to produce the global configuration option. It’s automatically added to the configuration pages of Hudson after deployment. It uses Jelly as scripting language (I think this is a bizarre decision, but it’s not important), you can find information about Jelly here. In our example the file looks like this:
<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:section title="TSL Integration"> <f:entry title="Field Test" help="${rootURL}/plugin/tsl/help-globalConfig.html" > <f:textbox name="tsl.field" value="${descriptor.field}" /> </f:entry> </f:section> </j:jelly>
config.jelly
is a file generated automatically by Maven, and it’s the Jelly Script file to produce the configuration option specific for the job. In our example the file looks like this:
<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 description="Check to enable this publisher for the job"> <f:checkbox name="tsl.enable" checked="${instance.enable}" /> </f:entry> </j:jelly>
And that’s all you need to develop a Publisher Hudson Plug-in. You can test it following the instructions in the Hudson wiki.
on Jan 27th, 2009 at 4:53 pm
This is a great article. I have followed the instructions above but the global settings are not persisting after restarting Hudson. What am I doing wrong? My configure method reads the variables and then saves them. However, I assume they should be read from XML after a Hudson restart??
Any help would be appreciated.
on Oct 6th, 2010 at 12:39 pm
thanks for this informations..