Jenkins中Jelly基礎、超鏈接、國際化


Jelly基礎

參考:https://wiki.jenkins-ci.org/display/JENKINS/Basic+guide+to+Jelly+usage+in+Jenkins

UI Samples Plugin

這個插件就是用來展示如何使用基於Stapler, Jelly, Groovy等技術的Jenkins UI 控件的。安裝這個插件對學習Jenkins插件開發非常有用。

 

創建*.jelly文件

一個基本的jenkins插件結構包括以下幾個部分:

  • pom.xml
  • src/main/java
  • src/main/resources
  • src/main/webapp

假如已經寫好一個類  src/main/java/org/myorganization/MyAction.java,要為這個類定義一個Jelly文件。

  1. 在resources目錄中創建一個與類名一一對應的目錄:  src/main/resources/org/myorganization/MyAction
  2. 在這個目錄中添加.jelly文件(不同的文件名會有不同的作用),如index.jelly。
  3. 然后就是編輯這個文件

 

預定義對象

一個目錄下的所有Jelly文件都跟和該目錄一一對應的某個類直接關聯。這個對應的類對象會綁定到jelly文件中名字為 it 的變量上,jelly文件中可以通過it變量調用類中的方法,調用代碼要用一對大括號包裹,前括號前加$。形式為:${insert code here}

 

例如在MyAction.java中定義了如下的方法

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>

方法名開頭的get被自動去掉了,剩余部分首字母變成小寫。建議使用java約定的命名方式(如getter方法都是get開頭的CamelCase形式)確保Jelly能夠找到正確的方法。

 

Jenkins中預定義對象主要有

it              

  與jelly文件直接關聯的類實例

instance      

  當前正在被配置的對象(在配置頁面中的一個區域內),例如BuildStep。如果不是重新配置而是剛添加了一個新的實例的話這個變量為null。

app            

   Jenkins(或Hudson)實例

descriptor

      與instance對象所屬類對應的Descriptor對象

h        

      hudson.Functions對象的實例,提供了很多非常有用的方法。

 

預定義URL變量

rootURL

      Jenkins實例的URL

resURL

     JavaScript, HTML等靜態webapp資源(cf.  Jenkins.RESOURCE_PATH)

imagesURL

     圖標等圖像資源路徑 ,實際就是resURL/images

 

應盡可能使用resURL而不是rootURL,因為resURL允許瀏覽器緩存,可以提高響應速度減輕服務器壓力。

只要在l:layout或l:ajax塊內,這些URL就已經定義好了,也就是說在任何的Jenkins頁面里都可以使用(如果頁面是通過ajax加載的,需要添加l:ajax標簽)。

 

Note that until 1.505 rootURL will be empty in the typical case of Jenkins running in development mode with no context path (http://localhost:8080/); it is used for creating server-absolute paths such as /some/path for direct links. As of 1.505 it will be /jenkins in test mode, to help remind you to use it! In the rare case that you need to pass a complete URL to an external service for some reason, use app.rootUrl instead (which takes into account “Jenkins URL” from the system /configure screen). Hyperlinks in HTML has a fuller treatment of this topic.

 

大多數情況下,jelly文件修改后不需要重啟Jenkins服務就能看到效果。修改文件然后重新請求頁面,修改后的jelly文件就會被加載了。  

 

帶Descriptors的對象(如Publisher)

  1. 定義一個不可變的類將所有的配置選項作為構造器的參數。然后給這個構造器加上@DataBoundConstructor注解,Jenkins通過這個注解就能知道如何實例化這個類的對象。
  2. 為配置選項字段添加getter方法,或者將配置選項字段改為public final。Jelly腳本中就可以讀取這些字段值到配置頁面中。
  3. 編寫Jelly片段文件(一般會叫config.jelly,可以查看基類的javadoc文檔看看可以使用哪些jelly文件名字),在jelly文件中展示所有的配置選項。最基本的形式如下(jelly元素的field屬性即是屬性的名字,也是構造器參數的名字,這個例子中jelly文件對應的類需要提供getPort方法或public port字段)。
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
  <f:entry title="${%Port}" field="port">
    <f:textbox />
  </f:entry>
  <f:entry title="${%Host}" field="host">
    <f:textbox />
  </f:entry>
</j:jelly>

${%...}為國際化標記(https://wiki.jenkins-ci.org/display/JENKINS/Internationalization)。

 

Help文件

插件可以使用src/main/resources/path/to/plugin/PluginName目錄中的help-FIELD.htmlhelp-FIELD.jelly文件。Jenkins會在對應的Filed元素后添加一個問號圖標,點擊圖標就會將幫助文件在配置頁面中內聯的渲染出來。help.htmlhelp.jelly會作為插件頂級的幫助文件。

 

表單驗證

在descriptor類中添加的doCheckFIELD方法,會被用於表單驗證邏輯。示例如下:

public FormValidation doCheckPort(@QueryParameter String value) {
  if(looksOk(value))  return FormValidation.ok();
  else                return FormValidation.error("There's a problem here");
}

這個方法中可以有多個指定了具體Filed的@QueryParameter("FIELD")注解參數,同時獲得多個參數值。可以表單field之間相互依賴關系的驗證。更詳細的內容可以查詢stapler的文檔。

 

默認值

可以使用頁面元素的default屬性為表單域設置默認值。即可以用字面值,也可以編程式的方式計算默認值(使用jelly預定義的變量,調用這些對象的方法)。示例如下:

<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
  <f:entry title="${%Port}" field="port">
    <f:textbox default="80" />
  </f:entry>
  <f:entry title="${%Host}" field="host">
    <f:textbox default="${descriptor.defaultHost()}/>
  </f:entry>
</j:jelly>

 

無Descriptor的對象(如ComputerListener)

參考插件:https://github.com/jenkinsci/sidebar-link-plugin

 

如果插件用了無Descriptor的對象,如ComputerListener。可以按下面的步驟,在配置頁面中增加一個插件類(Plugin的子類)可讀取的文本框。

  1. 重寫 plugin類的configure(StaplerRequest req, JSONObject formData)方法。這個方法會在用戶點擊配置頁面的保存按鈕是被調用。
  2. 在configure方法里,調用formData的提取數據方法獲取配置值,如optInt("port",3141),將獲取的數據保存在Plugin類的成員字段中。
  3. 在configure方法里,調用save()方法,將plugin類的可序列化字段持久化存儲。
  4. 在plugin類的start方法中,調用load(),插件啟動時重新加載持久化存儲的數據。
  5. 在與plugin類對應的位置(src/main/resources/path/to/plugin/className/config.jelly)創建config.jelly文件,編寫配置頁面視圖。在插件類的config.jelly中,用變量it代替變量instance,it.port可以引用當前使用的port參數值。help屬性使用創建插件時pom.xml中指定的artifactId引用插件的資源。
    <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="My Plugin">
        <f:entry title="${%Port}" help="/plugin/ARTIFACT_ID_GOES_HERE/help-projectConfig.html">
          <f:textbox name="port" value="${it.port}"/>
        </f:entry>
      </f:section>
    </j:jelly>
  6. 在src/main/webapp中創建help文件help-projectConfig.html。
  7. 正常啟動Jenkins(mvn hpi:run),查看效果。

 

HTML中的超鏈接

https://wiki.jenkins-ci.org/display/JENKINS/Hyperlinks+in+HTML

規則1:超鏈接不要使用絕對URL

  HTML中的超鏈接應該使用相對URL(如../foo/bar,  build/5/changes)或應用相對URL(以/開頭,如/job/foo/5, /manage)。但是前面不要用絕對路徑(如http://jenkins/foo/1)。讓瀏覽器將相對路徑絕對化。

  這條規則的原因是,經過反向代理等過程后,web應用無法知道客戶端用來訪問服務器的URL。但是反向代理都會保證URL中的路徑部分(context path+path info)是原封不動的,使用應用內部的相對路徑不會有任何影響。

  在JavaEE中,URL的路徑部分可分為兩段,先是context path,后面跟着Path Info。例如http://server.example.com/jenkins/job/foo/5,/jenkins為context path,/job/foo/5為path info。Jenkins開發者可以控制后者。

  • getUrl()方法可以在整個Jenkins中返回域對象的path info部分,如Buiild.getUrl()返回job/foo/32/(開頭沒有/,結尾的/不同版本並不一致)。
  • getAbsoluteUrl()在整個Jenkins中返回域對象的絕對路徑。不要用這個方法渲染超鏈接。
  • 在Groovy/Jelly/JavaScript中,rootURL變量代表了context path。生成相對的超鏈接格式為:<a href="${rootURL}/${it.url}">...</a> (in Jelly) 或 a(href:"${rootURL}/${my.url}", ...) (for Groovy) 

規則2:使用靜態資源前綴URL訪問靜態資源

  圖片,JavaScript腳本,樣式表等靜態資源在Jenkins運行中不會變化,應該使用靜態資源前綴的URL(/static/XXXXX)訪問,如/static/907dbcb0/plugin/foobar/abc.png。XXXXX部分是Jenkins為運行中的Jenkins Session持續期而生成的隨機字符串。請求的路由與不帶前綴的相同,但是帶了前綴后頭信息中會設置很長的過期時間,讓瀏覽器使用緩存。隨機數字是為了防止plugins/core更新后瀏覽器使用舊數據。

在Java中: Functions.getResourcePath()作為URL的前綴。在Jelly中使用resURL變量。

Functions.getResourcePath()+"/plugin/git/icons/git-32x32.png";

<img src="${resURL}/plugin/translation/flags.png" />

規則3:為email,IM等生成絕對路徑

如果以HTTP響應以為的方式提供服務數據,需要生成絕對路徑。可用Jenkins.getInstance().getRootUrl()方法,將返回管理員配置的絕對路徑。這是在Jenkins實例中准確獲取絕對路徑的唯一方法。

規則4:ConsoleNote必須為Path-Info

通過HyperlinkNote向控制台輸出中嵌入超鏈接時,使用/開頭的URL創建便攜的超鏈接(如果URL以/開頭,就會相對於context path處理)。這樣就算控制台note創建以后,Jenkins URL變了,超鏈接依然能正確渲染。

void foo(TaskListener listener) {
  listener.getLogger().println(
    HyperlinkNote.encodeTo("/configure","Please configure your Jenkins"));
}

在Jenkins輕易地創建指向不同對象的超鏈接,可以查閱ModelHyperlinkNote類(http://javadoc.jenkins-ci.org/?hudson/console/ModelHyperlinkNote.html)。

 

反向代理和Https

如果反向代理終止了HTTPS,Jenkins無法利用HttpServletRequest#isSecure()檢查傳輸是否安全。Jenkins.isRootUrlSecure()可以檢查管理員配置的Jenkins URL是否是Https。

 

其他與路徑有關的主題

https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+says+my+reverse+proxy+setup+is+broken

https://wiki.jenkins-ci.org/display/JENKINS/Running+Jenkins+behind+Apache

https://wiki.jenkins-ci.org/display/JENKINS/Running+Jenkins+behind+Nginx

 

國際化

https://wiki.jenkins-ci.org/display/JENKINS/Internationalization 

properties文件默認編碼為ISO-8859-1。靜態資源文件編碼為UTF-8。

Messages類

  Jenkins使用Localizer(https://java.net/projects/localizer/)生成Messages類,能夠以類型安全的方式訪問Message資源。src/main/resources/**/Messages.properties匹配的所以文件都會生成一個對應的Messages類。如過IDE找不到這些類,需要手動將target/generated-sources/localizer目錄加入源碼的根目錄。返回用於顯示的字符串的代碼(如Descriptor.getDisplayName())可以使用Messages類獲取本地化的消息。在運行時,適當的locale會被自動選擇。

  典型的工作流如下:

  1. 確定需要本地化的messages
  2. 將消息寫入MEssages.properties文件。即可以為每個package編寫一個,也可以整個module/plugin只用一個。
  3. 運行 mvn compile,生成Messages.java
  4. 更新代碼,使用最新生成的消息格式方法。

  如果消息中包含單引號('),需要再用一個單引號昨晚轉義('')。如果想使用英文撇號(’),可以用unicode字符 U+2019,在properties文件中寫成\u2019。

 

在Jelly文件中標記消息

 ${%xxxx} 標記指示stapler查找本地化資源, 如果沒有找到對應資源,就原樣輸出xxxx。

<h1>${%Output}</h1>

 帶參數消息

要渲染出的結果:

 <p>Click <a href="${obj.someMethod(a,b,c)}" >here</a></p>

foo.properties文件中內容為:

click.here.link = Click <a href="{0}" >here</a>

jelly中消息引用標記:

<p>${%click.here.link(obj.someMethod(a,b,c))}</p>

因為參數使用了的括號()包裹,所以普通文本中不能包含括號。

<h1>${%Path to file (.ipa or .apk)}</h1>     解析會出錯

這種情況下可以通過拆分文本,將括號排除在{% }標記外部

<h1>${%Path to file} (${%.ipa or .apk})</h1>    

 

多個參數

多個參數之間用 , 分隔(類似方法調用)。在properties文件中按參數位置引用 {0}為第一個參數,{1}為第二個參數......(按MessageFormat解析,參考:http://docs.oracle.com/javase/6/docs/api/java/text/MessageFormat.html

<p>${h.ifThenElse(x,"no error","error")}</p>

 

參數中再標記消息,不需要大括號{}包裹

<p>${h.ifThenElse(x,"%no error","%error")}</p>

 

help.html和help-FILED.html文件的本地化

默認help.html為English。然后再為xx語言創建help_xx.html文件即可。

 

翻譯

Translation Tool :命令行資源文件翻譯工具(https://wiki.jenkins-ci.org/display/JENKINS/Translation+Tool)

Translation Assistance Plugin :Adds a dialog box in Jenkins to translate and send missing keys.

Stapler plugin for IntelliJ IDEA: 利用反射提取java代碼中的資源到properties文件(mvn compile編譯之前會顯示錯誤)。

NetBeans plugin for Stapler 

 

要翻譯的內容

  • Messages.properties
  • jelly文件。可以先調用mvn stapler:i18n -Dlocal=fr,生成一個骨架文件*_fr.properties,所以條目值都為空。如果文件已經存在則添加之前不存在的新條目。留空的條目會回退到默認的locale。
  • 靜態HTML資源。foo_xx.html

 

翻譯完成度報告

http://www.simonwiest.de/glottr/report/

 


免責聲明!

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



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