有時候我們會發現,當我們想要做一些事情的時候,光透過 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 jsongroovy_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_NONEs = urllib2.urlopen(req, context=ctx)
result = s.read()
json_result = json.loads(result)
print json_result
相關資料
- Getting Groovy with Jenkins 投影片 — IBM 的測試工程師 Lorelei McCollum 在 Jenkins User Conference 2015 上的簡報