Introduction to Hudson plug-in development

Source: Internet
Author: User

I recently came into contact with Hudson plug-in development. I think it is quite interesting, but there are very few materials in this regard. So I simply summarized some of my learning materials.

1. About Hudson (also known as Jenkins)

Simply put, it is an open-source continuous integration software implemented in pure Java. It is generally used in Web containers, in the form of a separate war package, and an installation package embedded with the jetty server. It is well known in the field of continuous integration, and the biggest factor comes from its scalable plug-in mechanism and powerful plug-in support, currently, more than 400 free plug-ins support different continuous integration features. Hudson's plug-in mechanism allows developers to do many things through customization, including custom building steps, display methods of results, notification methods, integration with SCM Systems, testing and analysis, etc.

2. Plug-in development

Hudson is a Maven-based project, its plug-in development is also inseparable from Maven support, so it is necessary to have a little understanding of how Maven is used: http://maven.apache.org /. In addition, Hudson provides the HPI plug-in for plug-in development. The Hudson HPI (Hudson plug-in Interface) tool is a Maven plug-in that helps developers create, build, run, and debug the Hudson plug-in project.

After installing Maven, you can start to play with it:

1. Create a project

Find a clean place and execute mvn hpi: Create. At this time, MAVEN will check whether the HPI plug-in is installed (the maven plug-in developed by Hudson plug-in is called Hudson plugin interface ), if not, download and install the agent first. If an error is reported that the HPI command or alias cannot be identified, the maven agent cannot be found. Open the setting of Maven. XML file, add the maven plugin search path:

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

After the project is successfully created, the structure of a helloworld skeleton project is as follows:

Pom. XML-Maven pom file which is used to build your pluginsrc/main/java-java source file src/main/resources-plug-in jelly View File src/main/webapp-plug-in static Resources such as images and HTML files.

This is a standard Maven project structure, and then run the package to try: MVN package. Under the target directory, the plug-in is found to have been packaged into a jar package, and an HPI file exists. The HPI file is the standard plugin format of Hudson, which can be directly installed in the running Hudson Program (system settings- ins-advanced-upload INS)

LaterRun HPI: RunYou can enable the test mode Hudson, which has built-in plug-ins installed in the current development and can be accessed through localhost: 8080. The HPI: Run Command contains several subtasks: Start the jetty server, add Hudson as a web project, and install the current plug-in.

The work subdirectory of the plugin becomes the Home Directory of the current Hudson, and the Work/plugins subdirectory contains some HPI files (corresponding to the list of INS in the current Hudson ); you can find that the current directory contains a file with the suffix hpl, which corresponds to the current helloworld plug-in project. This is a simple text file, it internally describes the files (including classes, jars, and resources) related to the current project build. Each time the HPI: Run Command is executed, the HPI tool generates this file, while Hudson explains the file and directly loads the plug-in (without the need to pack the plug-in into an HPI Package). This method is also convenient for debugging during deployment.

2. Extended Functions

By default, a builder extension class (helloworldbuilder) is added to the generated helloworld project ). Hudson's extension mechanism is similar to eclipse and has the concept of extension and extension. The extension point is a set of interfaces, which allows third-party developers to implement this interface (providing extension implementation) to enhance system functions. The following applications are described around helloworldbuilder:

A building process usually includes:SCM checkout-check out source code pre-Build-Pre-compiled build wrapper-Prepare the Build Environment, set environment variables and other builder runs-execute the build, such as calling ant, make and so on-recording-record output, such as test result notification-Notification Member

Jenkins builder extension points are declared through the builder interface. By default, jenkins comes with ant and Maven builder extensions (create a job and add ant build step ...)

The generated helloworld class is as follows:

Public class helloworldbuilder extends builder {// execute the build by implementing the perform method to customize public Boolean perform (abstractbuild <?> AB, launcher, buildlistener BL) throws interruptedexception, ioexception ;{..} /* The build parameter describes a build of the current task, through which you can access some important model objects such: 1 Project current project object 2 workspace built workspace 3 result current build step result launcher is used to start build buildlistener this interface is used to check the status of the build process (START, failure, success ..) it can send some console information during the build process to the return value of the Hudson */perform method to tell Jenkins whether the current step is successful. If it fails, Hudson will give up the subsequent step. In addition, there is an internal static class that tells Hudson through the @ extension declaration that this is an extension implementation @ extension // This indicates to Jenkins that this is an implementation of an extension point. public static final class descriptorimpl extends buildstepdescriptor <builder> {public Boolean isapplicable (class <? Extends abstractproject> Aclass) {// whether return true is available for all project types ;}

/*** Builder display name. */Public String getdisplayname () {return "Say hello World ";}}

}

An implementation example of the build method (perform:

List <cause> buildstepcause = new arraylist (); buildstepcause. add (new cause () {Public String getaskdescription () {return "build step started by Hello builder" ;}}); listener. started (buildstepcause); // output the log argumentlistbuilder ARGs = new argumentlistbuilder () to the Hudson console; If (launcher. isunix () {args. add ("/bin/ls"); args. add ("-La");} else {args. add ("dir"); // windows} string homedir = system. ge Tproperty ("user. home "); args. add (homedir); try {int R; // call an external command. Use cmds to input commands and parameters; the stdout method redirects the standard output to the listener stream (output to the Hudson Web Console). The join waits for completion and returns results. // you can see that launcher is quite powerful .. R = launcher. launch (). cmds (ARGs ). stdout (listener ). join (); If (R! = 0) {listener. finished (result. failure); Return false ;}} catch (ioexception IOE) {IOE. printstacktrace (listener. fatalError ("execution" + ARGs + "failed"); // print an exception and mark the result as listener. finished (result. failure); Return false;} catch (interruptedexception IE) {IE. printstacktrace (listener. fatalError ("execution" + ARGs + "failed"); listener. finished (result. failure); Return false;} listener. finished (result. success );

3Add Configuration

Jenkins uses the jelly page rendering technology, which is an XML-based server page rendering engine that converts XML tags Based on jelly to corresponding HTML tags and outputs them to the client. The model object information is passed to the page through the jexl expression (equivalent to jstl of JSP ). Use. jelly is the suffix. In Hudson, the full name of the class is used to find the jelly page file corresponding to the model class, for example, org. sample. hudson. helloworldbuilder class, the corresponding page file should exist in the following location of the Resource Directory (with classpath as the root)

org/sample/hudson/HelloWordBuilder

In addition, Hudson uses a fixed naming method to determine whether the page file is a local configuration or a global configuration: config. Jelly provides local configuration; Global. Jelly provides global configuration.

A. Detailed description of local configuration

The content of config. Jelly will be included in the configuration of the extended function.
Take helloworldbuilder as an example. It extends the building steps of a Hudson job, so config. Jelly provides the configuration content corresponding to the building step.
Example:

<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 = "name" field = "name"> <F: textbox/> </F: Entry> </J: Jelly>

The entry indicates the HTML form field used for interaction. The title will be used as the label value of the form field.
Textbox indicates simple rendering of a text
You can add help instructions for form fields (the question mark button is displayed after the text box on the page. A prompt is displayed when you click it ):
Create help-{filename}.html under the same name directory and add help content to the file. The help content can be dynamic, that is, information can be pulled from the model for display. In this case, you need to change the HTML suffix to jelly, the file format is roughly as follows:

<J: Jelly xmlns: J = "JELLY: Core" xmlns: St = "JELLY: stapler" xmlns: D = "JELLY: define "> <div> welcome to $ {app. displayname }. // display name of the application (usually Hudson) enter your name in the field. </div> </J: Jelly>

Files with the jelly suffix are handed over to the jelly engine for execution during rendering, so dynamic display is supported.
Jexl expressionRule for replacing model data: $ {modelname. attrname} calls the get ** method of the corresponding module to obtain the value.
Description of built-in Model objects:

1 app Hudson Application Object: displayname Example 2 it current UI model object. In the builder extension example above, it corresponds to helloworldbuilder object $ {It. name} corresponds to a global tool class in builder's getname () method 3 h, providing static tool Methods

After being saved on the job configuration page, Hudson creates a builder object and injects the form value through the constructor.The constructor declaration is as follows:

@DataBoundConstructorpublic HelloWorldBuilder(String name) {   this.name = name;}

The builder must provide the getname method, so that the configuration can be in config. XML (Hudson uses XML to store the configuration information). The value can be automatically filled when the job configuration is re-opened.

 Regarding the validation of form values,Take the text domain name as an example:
Jelly automatically adds a script for Ajax verification during rendering, so when the text box loses focus, it will send a verification request to the server:

GET /job/TestProject/descriptorByName/org.sample.hudson.HelloWorldBuilder/checkName?value=xy HTTP/1.1Host: localhost:8080User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:6.0.1) Gecko/20100101 Firefox/6.0.1Accept: text/javascript, text/html, application/xml, text/xml, */*

Later, Hudson finds helloworldbuilder and finds the docheckname method (in the descriptor class). If not, the request is ignored.
Otherwise, the returned check results are displayed on the front-end.Sample implementation of the docheckname Method:

Public formvalidation docheckname (@ queryparameter string value) // @ queryparameter annotation indicates injection of the HTTP request parameter throws ioexception, servletexception {If (value. length () = 0) {return formvalidation. error ("Please set a name");} If (value. length () <4) {return formvalidation. warning ("isn' t the name too short? ");} Return formvalidation. OK ();}

B. Global configuration details

As described above, global. Jelly is the global configuration page, for example:

<F: Section title = "Hello World builder"> <F: entry Title = "French" Description = "check if we shocould say hello in French" Help = "/plugin/javaone-Sample/help-globalConfig.html"> <F: checkbox name = "hello_world.usefrench" Checked = "$ {descriptor. usefrench ()} "/> </F: Entry> </F: Section> // you can find the corresponding configuration section in Jenkins system settings.

Where$ {Descriptor. usefrench ()} calls the builder's (getdescriptor) to obtain the descriptor object and calls its usefrench Method for value;
Help declares the location of the Help content document;
Every time you save the global configuration, Jenkins will call the descriptor object and call its configure method to implement this method and provide its own customization:

Public Boolean configure (staplerrequest req, jsonobject formdata) throws formexception {usefrench = formdata. getboolean ("usefrench"); Save (); return Super. configure (req, formdata);} // save method is used to persist the configuration provided by the current Descriptor (through the get ** method) // The load method is used to inject persistent information into the current Descriptor (through the set ** method). Therefore, to make SAVE and load work properly, you need to provide the get/Set Method for configuration items.Use Cases: Execute load in the constructor method to perform global configuration such as to the current object. The configuration file uses the expression to call the get ** method of descriptor to display it to the front-end. When saving the system configuration, in the configure method, the configuration is read into the current object and persisted.

 

Iii. Other materials

Extended by Hudson javadoc: http://wiki.jenkins-ci.org/display/JENKINS/Extension+points

Hudson plug-in development Introduction: https://wiki.jenkins-ci.org/display /~ Martino/2011/10/27/The + jenkinsplugintotallysimpelguide

Introduction to implementing report release extension (publisher): http://www.theserverlabs.com/blog/2008/09/24/developing-custom-hudson-plugins-integrate-with-your-own-applications/

Example of an HTML report release extension (selenium-based report release extension ):

Https://github.com/jenkinsci/seleniumhtmlreport/blob/master/src/main/java/org/jvnet/hudson/plugins/seleniumhtmlreport/SeleniumHtmlReportPublisher.java

Hudson plugin overview-

Http://wiki.hudson-ci.org/display/HUDSON/All+Plugins+by+Topic

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.