Hudson插件開發簡介

近期接觸到Hudson的插件開發,以爲仍是比較好玩的,但目前這方面的資料而很是之少,因而將本身一些學習資料簡單概括了一下,算是拋磚引玉吧javascript

1、關於Hudson(又名Jenkins)html

     簡單說,它就是一個純java實現開源的持續集成軟件,通常搭載在web容器上用,有單獨war包的形式,也有內嵌jetty服務器的安裝包。在持續集成領域中至關出名,而其中最大的因素則源自其可伸縮的插件機制和強大的插件支持,目前已有超過400多款支持不一樣持續集成特性的免費可用插件。Hudson的插件機制容許開發者經過定製來作不少事情,包括自定義構建步驟、結果的展現方式、通知方式、與SCM系統的集成、測試和分析等等。前端

2、插件開發java

    Hudson是基於maven的項目,其插件開發也離不開maven的支持,所以有必要稍微瞭解下maven是怎麼用的:http://maven.apache.org/ 。此外,hudson提供了hpi插件來實現其插件開發。The Hudson HPI (Hudson Plug-in Interface) tool, 是一個Maven插件,可幫助開發者建立、構建、運行和調試Hudson插件項目git

     安裝完maven以後即可以開始玩了:github

    1    建立項目web

           找一個乾淨的地方,執行一下:mvn  hpi:create   此時maven會檢查當前是否安裝了hpi插件(hudson插件開發的maven插件,全稱爲hudson plugin Interface),若是沒有將先下載安裝;若是報錯提示 沒法識別 hpi命令或別名,那是maven找不到插件了,打開maven的setting.xml文件,添加maven插件查找路徑:ajax

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

 

建立項目成功以後,一個helloworld的骨架項目結構以下:apache

pom.xml -       Maven POM file which is used to build your plugin
src/main/java - java源文件
src/main/resources - 插件的Jelly 視圖文件
src/main/webapp - 插件的靜態資源 such as images and HTML files.

 

這是一標準的maven項目結構,緊接着執行一下打包試試: mvn package,在target目錄下發現插件打成了jar包,另外還有一個hpi文件。而hpi文件即是hudson的標準插件格式,能夠直接安裝到已運行的hudson程序中(系統設置-插件-高級-上傳插件)服務器

此後執行hpi:run 能夠開啓一個test模式的hudson,其內置安裝了當前開發中的插件,經過localhost:8080能夠訪問。hpi:run 命令包含了幾個子task:啓動jetty服務器,添加hudson爲web項目、安裝當前插件。 

插件的work子目錄成爲了當前Hudson的Home目錄,work/plugins子目錄則包含了一些hpi文件(對應於當前hudson中的插件列表);仔細點能夠發現當前的目錄中
有一個hpl爲後綴的文件,其對應了當前的helloworld插件項目;這是一個簡單的文本文件,其內部描述了與當前項目構建相關的文件(包括classes、jars和resources)每次執行hpi:run命令時,HPI工具都會生成該文件,而Hudson解釋該文件並直接加載該插件(而不須要把插件打成hpi的包)
此種方式也方便於部署期間的調試。

    2   擴展功能

         生成的helloworld項目默認添加了一個Builder的擴展類(名爲HelloWorldBuilder)。Hudson的擴展機制與Eclipse有些類似,也有擴展點和擴展的概念,擴展點便是一組接口,其容許第三方開發者實現該接口(提供擴展實現)來加強系統的功能。下面的應用將圍繞HelloWorldBuilder進行說明:

一次構建過程一般包括:
SCM checkout - check out出源碼
   Pre-build    - 預編譯
   Build wrapper  -準備構建的環境,設置環境變量等
   Builder runs   - 執行構建,好比調用calling Ant, Make 等等
   Recording    - 記錄輸出,如測試結果
   Notification    - 通知成員

 

 jenkins構建器的擴展點經過Builder接口聲明,在默認狀況下,jenkins自帶了Ant和Maven的builder擴展實現(新建一個job,能夠添加ant build step...)

生成的HelloWorld類以下:

public class HelloWorldBuilder extends Builder { //構建的執行經過實現perform方法來進行自定義
    public boolean perform(AbstractBuild<?> ab, Launcher launcher, BuildListener bl) throws InterruptedException, IOException;{ ..} /* Build參數是描述了當前任務的一次構建,經過它能夠訪問到一些比較重要的模型對象如: 1 Project 當前項目的對象 2 workspace 構建的工做空間 3 Result 當前構建步驟的結果 Launcher 用於啓動構建 BuildListener 該接口用於檢查構建過程的狀態(開始、失敗、成功..) 經過它能夠在構建過程當中發送一些控制檯信息給Hudson */ perform方法的返回值告訴jenkins當前步驟是否成功,若是失敗了Hudson將放棄後續的步驟。 此外有一個內部靜態類,該類經過@Extension聲明告訴Hudson,這是一個擴展實現 @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) { // 是否對全部項目類型可用
            return true; } /** 
* builder的顯示名.
*/
public String getDisplayName() {
return "Say hello world";
}
} }

 

 關於構建方法(Perform)的一個實現樣例:

List<Cause> buildStepCause = new ArrayList(); buildStepCause.add(new Cause() { public String getShortDescription() { return "Build Step started by Hello Builder"; } }); listener.started(buildStepCause); //向hudson控制檯輸出日誌
 ArgumentListBuilder args = new ArgumentListBuilder(); if (launcher.isUnix()) { args.add("/bin/ls"); args.add("-la"); } else { args.add("dir"); //Windows
 } String homeDir = System.getProperty("user.home"); args.add(homeDir); try { int r; //調用外部命令,cmds傳入命令和參數;stdout方法將標準輸出重定向到listener的流中(輸出到hudson的web控制檯),join等待完成並返回結果 //能夠看到launcher是至關強大的.. 
   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"));  //打印異常,標記結果
 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);

 

     3   添加配置

     Jenkins使用了Jelly頁面渲染技術,這是一個基於XML的服務端頁面渲染引擎,其將基於Jelly的xml標籤轉換爲對應的Html標籤並輸出到客戶端。模型對象的信息經過Jexl表達式被傳遞到頁面上(至關於Jsp的JSTL)。jelly文件以.jelly爲後綴,在hudson中使用類全名的形式來查找模型類對應的jelly頁面文件,如名爲org.sample.hudson.HelloWorldBuilder的類,其對應的頁面文件應該存在於resource目錄的如下位置中(以classpath爲根)

org/sample/hudson/HelloWordBuilder

此外hudson經過固定的命名方式來肯定頁面文件屬於局部配置仍是全局配置:config.jelly提供局部配置;global.jelly提供全局配置

     A  局部配置詳解

         config.jelly 的內容將被包含在擴展功能的配置中
                以HelloWorldBuilder爲例,其擴展的是一個Hudson Job的構建步驟,那麼config.jelly  提供的即是該構建步驟對應的配置內容
   樣例說明:

<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="名稱" field="name">
         <f:textbox />
  </f:entry>
</j:jelly>

 

   entry 表示用於交互的html表單域,title將做爲表單域label的值
   textbox 表示簡單的渲染一個text
   容許爲表單域增長幫助說明(在頁面上對應於文本框後面出現問號按鈕,一點擊可出現提示):
   在同名目錄下建立help-{fileName}.html,在該文件中添加幫助內容;幫助內容容許是動態的,便可以從模型中拉取信息進行顯示,這須要將html後綴改成jelly,而文件的形式大體以下:

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define">
  <div> Welcome to ${app.displayName}. //應用的Display名稱(通常就是Hudson) Enter your name in the Field. </div>
</j:jelly>

 

jelly後綴的文件在渲染時會交給jelly引擎執行,於是支持動態顯示能力。
jexl表達式替換模型數據的規則:${modelName.attrName}  調用對應模塊的get**方法得到值
關於內置模型對象的說明:

1  app  Hudson應用程序對象 如上面的displayName例子
2  it   當前UI所屬的模型對象,在上面的Builder擴展例子中則對應於HelloWorldBuilder對象
       ${it.name} 對應於builder的getName()方法
3  h   一個全局的工具類,提供靜態工具方法

    經過Job配置界面保存以後,hudson會建立builder對象,並將表單值經過構造器注入,構造器聲明以下:

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

 


而builder必須提供getName方法,這樣可將配置到config.xml中(hudson使用xml存儲配置信息)在從新打開job配置時可自動填值

  關於表單值的校驗,以文本域name爲例:
  jelly在渲染時自動增長了ajax校驗的功能腳本,因而文本框失去焦點時會往服務端發送校驗請求:

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

 

此後Hudson找到HelloWorldBuilder,查找doCheckName方法(在Descriptor類中查找),若是沒有找到則忽略該請求
不然返回檢查結果在前端展現。doCheckName方法的樣例實現

public FormValidation doCheckName(@QueryParameter String value)  //@QueryParameter註解表示注入http請求參數
                                      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.jelly 爲全局配置頁面,示例:

<f:section title="Hello World Builder">
   <f:entry title="French" description="Check if we should say hello in French" help="/plugin/javaone-sample/help-globalConfig.html">
      <f:checkbox name="hello_world.useFrench" checked="${descriptor.useFrench()}" />
   </f:entry>
</f:section>

 

//在jenkins的系統設置中能夠找到相應的配置段落。

其中${descriptor.useFrench()} 調用builder的(getDescriptor)獲得Descriptor對象,調用其useFrench方法進行取值;
help聲明瞭幫助內容文檔位置;
在每次保存全局配置時,jenkins都會調用調用該descriptor對象,並調用其configure方法,能夠實現該方法並提供本身的定製:

public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { useFrench = formData.getBoolean("useFrench"); save(); return super.configure(req,formData); }

 

//save方法用於將當前Descriptor所提供的配置持久化(經過get**方法)
//load方法用於將持久化的信息注入到當前Descriptor中(經過set**方法)
所以爲了使save和load能正常工做,須要提供配置項的get/set方法
使用場景:在構造器方法中執行load,將全局配置諸如到當前對象中;配置文件經過表達式調用descriptor的get**方法顯示到前端;在保存系統配置時,configure方法中將配置讀入當前對象,並持久化。

 

3、其餘資料

Hudson的擴展點JavaDoc:http://wiki.jenkins-ci.org/display/JENKINS/Extension+points

Hudson插件開發簡單介紹:https://wiki.jenkins-ci.org/display/~martino/2011/10/27/The+JenkinsPluginTotallySimpelGuide

實現報告發布擴展(Publisher)的介紹:http://www.theserverlabs.com/blog/2008/09/24/developing-custom-hudson-plugins-integrate-with-your-own-applications/

一個Html報告發布擴展的例子(基於Selenium的報告發布擴展):

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

Hudson插件大全介紹 - http://wiki.hudson-ci.org/display/HUDSON/All+Plugins+by+Topic
   

原文地址:http://blog.csdn.net/littleatp2008/article/details/7001793

相關文章
相關標籤/搜索