首頁 > 軟體

Jenkins Plugin 基礎開發入門

2020-06-16 17:26:18

引子:Jenkins 是目前階段各大公司運用持續整合的主要輪子,而 Jenkins 能否發揮如此神威的主要原因即在於其眾多的 Plugins 可以快速實現客製化化需求。筆者因工作需要,體驗了一把從零入門 Jenkins Plugin 開發。現把經驗總結形成本文。

0x00 弄清 Jenkins 的主要概念

先來看看 Jenkins 自己搭建的 CI 環境:Jenkins on Jenkins ,再結合下面這張官網給出的解釋持續交付工作流程的示意圖,簡單學習 & 增加感性認識。

IBM 給出資料指出 Jenkins 在實現上有三個重要概念:

Stapler

  • Stapler 可以自動為應用程式物件系結 URL,並建立直觀的 URL 層次結構。而Jenkins 的類物件和 URL 係結就是通過 Stapler 來實現的,通過該技術我們可以快速存取對應的Job及其相應資源。

持久化

  • Jenkins 使用檔案來儲存資料(所有資料都儲存在$JENKINS_HOME)。

外掛

  • Jenkins 的物件模型是可延伸的,通過 Jenkins 提供的可延伸點,我們可以開發外掛擴充套件 Jenkins 的功能。
  • 所有的 Plugin 都是在 Jenkins Master 上執行的。

0x01 選擇 Jenkins 的擴充套件功能介面

Jenkins 擁有極多的外掛,而這些外掛的開發都是基於 Jenkins 的擴充套件功能介面(Jenkins Extension Points)實現的。為了盡可能的實現客製化化,Jenkins 的提供的擴充套件功能介面極多,詳情可見 Jenkins Extension Points

但這並不意味著我們需要一一掌握所有的擴充套件功能介面,Jenkins 官方提供的 資料 指出:

通常,一次構建過程包括如下幾個步驟:
1.SCM checkout:檢出原始碼,用於指定構建的目標。
2.Pre-build steps:預編譯。
3.Build wrapper set up:構建環境準備。
4.Builder runs:執行構建的核心過程,例如呼叫Ant,Make等。
5.Recorder runs:記錄構建過程中的輸出,例如測試結果等。
6.Notifier runs:根據結果傳送通知。

而這其中,除了 Pre-build 僅僅是 huson.tasks 的一個 Interface以外。其餘五個擴充套件功能介面就是我們需要關注的重點:

  1. hudson.scm.SCM
  2. hudson.tasks.BuildWrapper
  3. hudson.tasks.Builder
  4. hudson.tasks.Recorder
  5. hudson.tasks.Notifier

當然,如果想實現其他更複雜的功能,可以直接參考 官方文件 以及 官方提供的外掛原始碼列表

0x02 搭建 Jenkins 開發環境

建立外掛工程目錄

按照 Jenkins 外掛開發的要求設定完 maven 的 settings.xml 組態檔之後,執行以下命令:

mvn -U org.jenkins-ci.tools:maven-hpi-plugin:create -DgroupId={your.gound.id} -DartifactId={your.plugin.id}

其中,your.groud.id 和 your.plugin.id 填你外掛的具體對應的值。命令執行之後,該目錄下會產生一個名稱是 {your.plugin.id} 的 HelloWorld 外掛工程目錄。

偵錯外掛

由於我們的 Plugin 的相關設定已由 Maven 工程的 pom.xml 定義好了,所以我們的僅需執行如下命令即可進行偵錯:

mvn hpi:run

這句簡單的命令就已經包含了諸如啟動 Jetty 伺服器,將 Jenkins 作為一個 Web 服務增加至上訴伺服器以及在 Jenkins 中安裝我們剛寫生成的 HelloWorld 外掛等一系列任務。

一旦上述過程成功執行,我們就可以可以在瀏覽器中通過下面的 URL 存取我們剛剛搭建好的 Jenkins 的主頁:

http://localhost:8080

這時我們就可以檢查我們編寫的外掛是否滿足我們的設計需要了。

發布及安裝外掛

Jenkins 的外掛通過 hpi 檔案格式發布,所以在發布前,需要通過如下命令進行打包:

mvn package

命令執行完成之後,即可在target目錄下的生成外掛的 hpi 檔案和 jar 檔案。

然後,我們無論是選擇將 hpi 檔案拷貝到 Jenkins Home 路徑下的 plugin 目錄中,或者選擇通過 Jenkins 外掛管理上傳安裝該 hpi 檔案,均可完成外掛的安裝。

0x03 梳理 Jenkins Plugin 工程結構

雖然 Jenkins 也支援Groovy 進行UI 開發,Jenkins 主要是用 Jelly 來進行 UI 管理。而 Jelly UI 技術的主要原理是通過伺服器端的渲染引擎將 Jelly 定義好的 XML 檔案渲染成用戶端需要的 HTML,Javascript 和 Ajax 等。

初步入門 Jenkins Plugin 的人(例如筆者自己)往往最困惑的一點就是如何理清 Jenkins Plugin 的工程結構以及 Plugin 的Jelly到底該怎麼寫。

通過上面的 mvn 指令我們生存的工程目錄具有如下的布局結構:

  • pom.xml - Maven POM 檔案,用於設定外掛的設定
  • src/main/java - 外掛的 Java 原始檔
  • src/main/resources - 外掛的 Jelly 檢視檔案
  • src/main/webapp - 外掛的靜態資源,如圖片或 HTLM 等

0x04 Jelly UI 入門

弄清楚了工程結構,剩下的事情就是到底怎麼用 jelly 來寫外掛的 UI 了。而這無非也就是需要弄明白三件事情:

  1. 如何為指定物件建立一個 Jelly UI 頁面;
  2. 如何讀取 Jelly 中的使用者輸入;
  3. 如何操控 Jelly 反餽資訊。

如何為指定物件建立一個 Jelly UI 頁面

前面說到,工程的目錄結構中:

  • src/main/java - 外掛的 Java 原始檔
  • src/main/resources - 外掛的 Jelly 檢視檔案

而 Jenkins 如何將兩者之前建立起對應關係的呢?簡單來說根據路徑結構的一致性來建立關係。

假設你建立了一個java類,路徑為

src/main/java/org/sample/HelloWorldBuilder.java

則增加Jelly檔案需要在resources資料夾中建立與類同名的目錄:

src/main/resources/org/sample/HelloWorldBuilder/

需要說明的是,Jenkins 通過固定的命名方式來確定頁面檔案屬於區域性設定還是全域性設定:config.jelly 為區域性設定;global.jelly 為全域性設定。

這裡它們的區別在有點類似於區域性變數與全域性變數的區別。gloabal.jelly 更多的用於讀取儲存與某個具體構建無關的設定資訊。而具體的構建本身的相關引數基本都由 config.jelly 進行處理。

如果我們需要建立的是一個區域性的設定(大多數情況),那麼我們就在上述路徑下增加檔案config.jelly,路徑如下:

src/main/resources/org/sample/HelloWorldBuilder/config.jelly

如何讀取 Jelly 中的使用者輸入

那麼我們有如何存取 Jelly 中的資訊呢?最為基礎的方法就是通過 Descriptor 進行頁面和資料的系結了。

假設我們在 jelly 按如下方式進行定義:

<f:entry title="Name" field="name">

那麼與之對應的,我們就可以在對應的類裡進行如下設定了:

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

那麼當 UI 中的資料提交之時, Jenkins 會根據傳過來的具體資料呼叫建構函式來建立物件。

在類中增加getter方法,或者將變數設定為public final。這樣可以還讓Jelly指令碼將數值顯示到設定資訊頁面。

public String getName() {
   return name;
}

在內部實現的DescriptorImpl類中,我們也可以選擇增加doCheckFIELD()函數,來進行設定檢查。在引數上可以增加@QueryParameter註解來傳入附近位置的資料。

public FormValidation doCheckName(@QueryParameter String value) 
    throws IOException, ServletException {
  if (value.length() == 0) {
    return FormValidation.error("Please set a name");
  }
  if (value.length() &lt; 4) {
    return FormValidation.warning("Isn't the name too short?");
  }
  return FormValidation.ok();
}

當然,我們也可以使用各種 Jelly 控制元件,如textbox,checkbox 以及 validateButton等等。具體的使用方法,可以參考以下文件,這裡就不一一展開了。

參考文件:jenkinsci/ui-samples-plugin

如何操控 Jelly 反餽資訊

首先,我們先來看看 Jelly 如何存取專案中的其它資源。預設情況下, Jenkins 已經定義了以下物件:

  • app - Jenkins
  • it - Jelly UI 係結的類
  • instance - Jelly UI 所對應的正在被設定的物件
  • descriptor -與 instance 所對應的 Descriptor
  • h - husdon.Functions 的範例

所以我們如果在類中設定了:

public String getMyString() {
    return "Hello Jenkins!";
}

而按如下方法編寫其對應的 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">
    ${it.myString}
</j:jelly>

那麼,頁面上就能呼叫出類的方法,顯示出”Hello Jenkins!”了。

區域網內利用GitLab+Jenkins自動生成GitBook並行布(Nginx)  http://www.linuxidc.com/Linux/2016-05/131136.htm

Linux+Git+Maven+Jenkins+Neuxs自動化編譯環境搭建 http://www.linuxidc.com/Linux/2016-02/128652.htm

CentOS 7上安裝Jenkins  http://www.linuxidc.com/Linux/2016-11/137548.htm

CentOS6安裝Jenkins  http://www.linuxidc.com/Linux/2016-05/131365.htm

使用Jenkins設定Git+Maven的自動化構建 http://www.linuxidc.com/Linux/2016-02/128641.htm

Jenkins+Maven+Git搭建持續整合和自動化部署的設定手記 http://www.linuxidc.com/Linux/2015-06/118606.htm

Jenkins的分散式構建及部署——節點  http://www.linuxidc.com/Linux/2015-05/116903.htm


IT145.com E-mail:sddin#qq.com