使用 Groovy 語言自動操作 Jenkins

有時候我們會發現,當我們想要做一些事情的時候,光透過 Jenkins 的 Web GUI 介面很難做到,而會想知道 Jenkins 是不是有 API 可以讓我們操作,比方說。

  • 我們在一個 Jenkins 主機上面跑了很多 build job,然後我們享用另外一個頁面 / app,彙整每個 build 的狀況,像是列出我們指定範圍內的 job 中失敗的 job。
  • 或是,我們有好幾個單元測試的 job,我們想要知道這些 job 最近幾次 build 的覆蓋率是多少。
  • 批次刪除:因為某個緣故,我們可能一次失敗了好幾次,我們想把這些失敗的 build 全部刪掉,但如果只從 Jenkins 的 Web GUI,卻只能夠一筆一筆刪除,這點再 Jenkins 的官方論壇上經常有人討論,但是 Jenkins 官方並沒有加入這個功能的計畫。

Jenkins 並沒有提供我們所習慣的 Web API,但是我們可以透過要求 Jenkins 執行特定的腳本(script ),達到上面我們想要做的事情,而如果我們想要撰寫自己的 client,讀取 Jenkins 上的資料,或是其他的操作,也可以透過 HTTP Post 的方式,把腳本送到 Jenkins 上執行。—說起來這還頂危險的,如果沒有對 Jenkins 加上保護,等於可以讓人很容易就破壞了整套 Jenkins 上的資料,所以,不管怎樣,Jenkins 主機都應該放在內網,而且加上密碼保護。

我們使用 Groovy 語言撰寫 Jenkins 上的腳本,Groovy 是一套可以讓我們操作 Java 物件的物件導向腳本語言,要學習這套語言,最快的方式應該是去 Learn X in Y minutes 網站上,參考 Learn Groovy in Y Minutes 這一篇。

接著,連往你的 Jenkins 主機的 /script 目錄下,就可以看到一個文字輸入區域,在這邊可以輸入你要執行的程式碼,你也可以從 Manage Jenkins -> Script Console 進入這個畫面。而如果你要用自己的 HTTP client 要求 Jenkins 執行指定的工作,也可以把要執行的程式,post 到主機的 scriptText 路徑即可。

Jenkins 所提供的 Groovy/Java API

在撰寫程式的時候,我們大概都會從 Jenkins(jenkins.model.Jenkins)這個 class 開始,這個 class 中有一個 singleton instance, 這個 singleton instance 代表的是我們當前整台 Jenkins 主機的狀態,我們就可以從這裡為起點,抓取各種我們想要的資料,或是建立新的 job、刪除某些 build 等工作,至於每個物件能做什麼事情,主要還是要參考 Jenkins 的 Java Doc

Jenkins 裡頭的物件關係大概是

  • Jenkins Singleton Instance – 整台 Jenkins 主機,可以用 getItem 等 method 取得主機上的各個編譯專意(Item)
  • Item (hudson.model.AbstractProject),代表的是某個編譯專案,底下會有很多的 Build
  • Build(hudson.model.AbstractBuild),我們可以從這裡取得編譯的結果(Status),而在每一次的編譯工作,也會有很多的 Action
  • Action(hudson.model.Action),像我們在每次編譯過程中,會需要先去抓取最新版的程式碼、執行編譯指令、archive 編譯出來的檔案、產生單元測試與覆蓋率報告等… 這些都是 action

以我們想要列出所有編譯失敗的 job 來說,我們可以寫這樣的程式:

def failed_items = []
Jenkins.instance.allItems.findAll { item -> 
  item.disabled != true &&
  item.getLastBuild().result != Result.SUCCESS
}.each { item ->
  failed_items.add(item.name)
}
failed_items

如果想要知道某些特定專案的覆蓋率,我們可以這樣寫:

def jobs = [“APITestIOS”, “APITestMac”, “DBTestIOS”, “DBTestMac”, “PlayerPolicyTestIOS","PlayerPolicyTestMac"]
def results = [:]
jobs.each { job -> 
    def result = Jenkins.instance.getItem(job).getLastSuccessfulBuild().getAction(hudson.plugins.cobertura.CoberturaBuildAction).getResult().getResults()
    results.put(job, result)
}
results

在 Jenkins 的官網上,也可以找到不少 範例

與 HTTP client 的整合

如果我們想用另外一個 client,抓取 Jenkins 上的資料,我們可以考慮把拿到的東西轉成 JSON 格式。Groovy 的函式庫本身提供我們一個 Java 物件轉換成 JSON 的工具,假如我們要用 Python 的 urllib,抓取某台 Jsnkins 上的資料,或許可以這樣寫

import urllib
import urllib2
import ssl
import base64
import json

groovy_script = '''def jobs = [“APITestIOS”, “APITestMac”, “DBTestIOS”, “DBTestMac”, “PlayerPolicyTestIOS", "PlayerPolicyTestMac"]
def results = [:]
jobs.each { job -> 
    def result = Jenkins.instance.getItem(job).getLastSuccessfulBuild().getAction(hudson.plugins.cobertura.CoberturaBuildAction).getResult().getResults()
    results.put(job, result)
}
println groovy.json.JsonOutput.toJson(results)
'''url ="https://YOUR_JENKINS_HOST/scriptText"parameters = {'script':groovy_script}
data = urllib.urlencode(parameters)

req = urllib2.Request(url=url, data=data)
username = 'username' # 如果你的 Jenkins 設了帳號密碼
password = 'password' 
base64string = base64.b64encode('%s:%s' % (username, password))
req.add_header("Authorization", "Basic %s" % base64string)  
ctx = ssl.create_default_context() # 如果你的 Jenkins 在內網,而且是不安全的 https
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

s = urllib2.urlopen(req, context=ctx)
result = s.read()
json_result = json.loads(result)
print json_result

相關資料

This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

About zonble

iOS Developer at KKBOX.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *