jenkins插件開發


https://jenkins.io/doc/developer/

1. 向導

  jenkins是一個強大的插件系統,開發者使用插件,幾乎可以影響到所有的jenkins操作。這個章節演示了簡單的插件功能。

1.1 准備插件的開發環境

  安裝JDK環境,安裝maven,保證mvn路徑被添加到path變量。

1.2 創建插件

  打開命令行,進入我們希望的目錄中,然后執行

mvn -U archetype:generate -Dfilter=io.jenkins.archetypes:plugin -DarchetypeCatalog=remote

  運行結果

…
Choose archetype:
1: remote -> io.jenkins.archetypes:empty-plugin (Skeleton of a Jenkins plugin with a POM and an empty source tree.)
2: remote -> io.jenkins.archetypes:global-configuration-plugin (Skeleton of a Jenkins plugin with a POM and an example piece of global configuration.)
3: remote -> io.jenkins.archetypes:hello-world-plugin (Skeleton of a Jenkins plugin with a POM and an example build step.)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 3 
Choose io.jenkins.archetypes:hello-world-plugin version:
1: 1.1
2: 1.2
3: 1.3 Choose a number: 3: 3 
[INFO] Using property: groupId = unused
Define value for property artifactId: demo 
Define value for property version 1.0-SNAPSHOT: : 
[INFO] Using property: package = io.jenkins.plugins.sample
Confirm properties configuration:
groupId: unused
artifactId: demo
version: 1.0-SNAPSHOT
package: io.jenkins.plugins.sample
 Y: : y 

  以上標出了關鍵的地方:

  1. 選擇hello-word-plugin作為我們的插件結構
  2. 選擇1.3最新版本
  3. artifactid是強制要求的,而且在jenkins中運行時要求唯一,我們設置為demo。
  4. 默認是 1.0-SNAPSHOT作為開發的版本號。(maven中的版本號區別可以查看: 這里
  5. 最后最列舉出來的信息進行確認Y

  以上會創建一個目錄,名字與artifactid的值一致(這里的值是demo),而且里面有一些基本的可運行的插件結構。執行以下指令來校驗這個插件源碼是否可以運行:

$ mv demo demo-plugin
$ cd demo-plugin
$ mvn verify

  這里第一步就是重命名這個文件夾,接着verify會下載一系列依賴,然后進入生命周期,包括FindBugs靜態分析和測試,直到顯示如下信息:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 06:11 min
[INFO] Finished at: 2017-03-02T14:14:34+01:00
[INFO] Final Memory: 73M/872M
[INFO] ------------------------------------------------------------------------

1.3 構建和運行插件

  maven的HPI插件用來構建和打包jenkins插件,這個插件提供了一個簡單的方式來運行插件:

mvn hpi:run

  以上指令會運行一個jenkins實例(這個jenkins實例的數據保存在插件目錄的work目錄下),在 http://localhost:8080/jenkins/,然后自動打開一個控制台(這個控制台對應jenkins實例),控制台顯示

INFO: Jenkins is fully up and running

  接着我們打開一個瀏覽器訪問http://localhost:8080/jenkins/,在jenkins中創建一個自由風格的項目,在構建設置中,啟用我們的插件“Say Hello Word”,在出現的選項中隨便輸入一個問候語“Hello Jenkins!”,然后保存,進行項目構建,打開這次構建的控制台,可以看到我們之前輸入的值,被輸出到控制台上了:

Started by user anonymous
Building in workspace /Users/mrjenkins/demo/work/workspace/testjob
Hello, Jenkins! 
Finished: SUCCESS

1.4 擴展插件

  這次通過以下特征來擴展插件:

  1. 用合適的數據結構來保存我們的問候語,而不是僅僅在構建控制台中輸出
  2. 添加一個新的頁面來顯示我們用過的問候語

 1.4.1 記錄問候語

  首先,在HelloWorldBuilder所在的包中創建一個類HelloWorldAction:

package io.jenkins.plugins.sample;
import hudson.model.Action;
public class HelloWorldAction implements Action {
    @Override
    public String getIconFileName() {
        return null;
    }
    @Override
    public String getDisplayName() {
        return null;
    }
    @Override
    public String getUrlName() {
        return null;
    }
}

  Action都是jenkins的基礎構建擴展單位,這些單位可以訪問並且保存許多對象,而且還可以把這些對象顯示到界面上。

  我們往這個Action類中添加我們希望保存的數據(私有字段和對應的geter、setter):

(...)
public class HelloWorldAction implements Action {
    private String name; public HelloWorldAction(String name) { this.name = name; } public String getName() { return name; }
    (...)

  現在,需要我們在構建的時候,生成這個類的實例,在HelloWorldBuilder類的perform方法中,添加如下一行標注的代碼:

(...)
    @Override
    public void perform(Run<?, ?> run, FilePath workspace, Launcher launcher, TaskListener listener) throws InterruptedException, IOException {
        run.addAction(new HelloWorldAction(name)); 
        if (useFrench) {
            listener.getLogger().println("Bonjour, " + name + "!");
        } else {
            listener.getLogger().println("Hello, " + name + "!");
        }
    }
(...)

  保存后,mvn hpi:run來運行插件。之后每次進行構建,上面的Action都會被應用。可以通過查看build.xml來確認,這個文件在這里work/jobs/JOBNAME/builds/BUILDNUMBER/。文件大致如下:

<build>
  <actions>
  <hudson.model.CauseAction> 
      <causes>
        <hudson.model.Cause_-UserIdCause/>
      </causes>
    </hudson.model.CauseAction>
    <io.jenkins.plugins.sample.HelloWorldAction plugin="demo@1.0-SNAPSHOT"> 
      <name>Jenkins</name> 
    </io.jenkins.plugins.sample.HelloWorldAction>
  </actions>
  (...)
</build>

  對於以上三個標注的地方:

  1. 代表了構建的原因(如果觸發這次構建)也被作為action來保存了,這里指出了是匿名用戶觸發的構建
  2. 這是我們新建的Action
  3. 這個name值就是我們在構建配置中設置的值

1.4.2 添加個頁面來顯示數據

  首先,回到HelloWorldAction中修改如下函數的返回值:

    @Override
    public String getIconFileName() {
        return "document.png"; 
    }

    @Override
    public String getDisplayName() {
        return "Greeting"; 
    }

    @Override
    public String getUrlName() {
        return "greeting"; 
    }

  分別代表了多出的側邊欄的圖標、標題,以及地址(http://JENKINS/job/JOBNAME/BUILDNUMBER/greeting/)。

  接着,以上地址的頁面需要被配置。在jenkins中創建視圖,通過Jelly來實現。

  在src/main/resources/io/jenkins/plugins/sample/中創建一個目錄,名為HelloWorldAction。這個目錄對應我們的HelloWorldAction類,代表這個目錄中的資源給對應的類來使用。目錄中有如下資源:

  1. config.jelly:代表構建配置中的表單界面
  2. config*.properties:contain the localizations for the build step configuration
  3. help*.html:provide the localized inline help for the configuration

  在以上目錄(src/main/resources/io/jenkins/plugins/sample/HelloWorldAction/)中創建一個 index.jelly,這個界面會顯示在http://JENKINS/job/JOBNAME/BUILDNUMBER/greeting/中。index.jelly內容如下:

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler">
    <l:layout title="Greeting"> 
        <l:main-panel> 
            <h1> Name: ${it.name} 
            </h1>
        </l:main-panel>
    </l:layout>
</j:jelly>

  對於以上四個標注的地方:

  1. layout標簽是jenkins提供的一個基礎界面容器,包含了header、footer、主內容區域,側邊欄等
  2. main-panel標簽中的內容代表了容器中的主內容
  3. jelly中可以使用任意html標簽
  4. 這是一個JEXL表達式,it代表了這個視圖所屬的Java對象(類似於this),在這個例子中就是指向了HelloWorldAction實例,it.name等價於調用了這個屬性的getter,也就是調用了getName方法

  做好以上配置后,當我們訪問http://JENKINS/job/JOBNAME/BUILDNUMBER/greeting/時,jelly以及里面的name數據就顯示出來了

 1.4.3 為頁面添加側邊欄

  以上的顯示的界面中沒有側邊工具欄,這里我們要做的就是把側邊工具欄顯示出來。要實現這個效果,

  1. 在Action中獲取到這次構建的引用
  2. 從這個引用中獲取到工具欄fragment
  3. 將這個fragment引用到我們的界面中

  實現第一步,讓HelloWorldAction來實現RunAction2這個接口,里面有兩個方法:

  • onAttached(Run):called when the run is first attached to a build
  • onLoad(Run):called when the action and run are loaded from disk
(...)
import hudson.model.Run;
import jenkins.model.RunAction2;
public class HelloWorldAction implements RunAction2 { 
    private transient Run run; 
    @Override
    public void onAttached(Run<?, ?> run) {
        this.run = run; 
    }
    @Override
    public void onLoad(Run<?, ?> run) {
        this.run = run; 
    }
    public Run getRun() { 
        return run;
    }
(...)

  對於以上標注的兩個個地方:

  1. 被這個關鍵字修飾的run,不會隨着這個action序列化到硬盤上
  2. 使我們獲取到的run,可以用在jelly視圖中

   然后在jelly中引入run提供的側邊工具欄:

(...)
    <l:layout title="Greeting">
        <l:side-panel> 
            <st:include page="sidepanel.jelly" it="${it.run}" optional="true" /> 
        </l:side-panel>
        <l:main-panel>
          (...)
        </l:main-panel>
    </l:layout>
(...)

  類似於main-panel,side-panel代表了側標欄。接着include標簽,可以從這個標簽的it屬性所指向的對象中,引入page所指向的視圖,效果就是從run中引入了sidepanel.jelly視圖。然后將這個標簽設置為可選的,這樣一來,當sidepanel.jelly不存在時也不會報錯了

  以上配置后,http://JENKINS/job/JOBNAME/BUILDNUMBER/greeting/就有側邊欄了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM