差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

jenkins:restapi:get_artifacts [2016/12/25 23:43]
tony [Sample code]
jenkins:restapi:get_artifacts [2023/06/25 09:48]
行 1: 行 1:
-{{tag>​jenkins}} 
-====== Get Artifacts with RestAPI ====== 
-===== Problem ===== 
-為了節省軟體的反安裝、下載與安裝時間,我們有隻script,會去jenkins抓某個固定位置的最新安裝程式並安裝。然而,開發過程會因為新功能或修bug等原因產生branch;原本的腳本並無法根據branch去下載安裝程式,也因此花了些時間去研究並解決這個問題。 
-===== How to? ===== 
-jenkins既然有RestAPI,應該就有辦法讓人可以存取到它專案相關資訊吧?​ 為了達到我們目的,其中會包含幾個步驟:​ 
-  - 取得專案build列表。 
-  - 取得branch吻合的build URL。 
-  - 取得此build的artifact列表。 
-  - 過濾想要的artifacts。 
-以專案名稱Example為例,其專案的URL為:​ 
-<​code>​ 
-http://​tonylin.idv/​job/​Example 
-</​code>​ 
-==== 取得專案build列表 ==== 
-首先可以透過此URL去搜尋所有build資訊:​ 
-<​code>​ 
-http://​tonylin.idv/​job/​Example/​api/​json?​tree=builds[*] 
-</​code>​ 
-以一個build的結果如下:​ 
-<code json> 
-{ 
-  "​builds":​ [ 
-  { 
-  "​actions":​ [ 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {} 
-  ], 
-  "​artifacts":​ [ 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {} 
-  ], 
-  "​building":​ false, 
-  "​description":​ "​origin/​integration_testing",​ 
-  "​displayName":​ "#​6611",​ 
-  "​duration":​ 375922, 
-  "​estimatedDuration":​ 366451, 
-  "​executor":​ null, 
-  "​fullDisplayName":​ "​Example #​6611",​ 
-  "​id":​ "​6611",​ 
-  "​keepLog":​ true, 
-  "​number":​ 6611, 
-  "​queueId":​ 335, 
-  "​result":​ "​SUCCESS",​ 
-  "​timestamp":​ 1481712191068,​ 
-  "​url":​ "​http://​tonylin.idv/​job/​Example/​6611/",​ 
-  "​builtOn":​ "",​ 
-  "​changeSet":​ {}, 
-  "​culprits":​ [ 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {}, 
-  {} 
-  ], 
-  "​fingerprint":​ [] 
-  } 
-] 
-} 
-</​code>​ 
-==== 取得branch吻合的build URL ==== 
-由於前一個URL使用[*]是列出所有項目,但其實我們只需要知道branch、build結果、build URL與build number,可以透過以下URL去做query:​ 
-<​code>​ 
-http://​tonylin.idv/​job/​Example/​api/​json?​tree=builds[description,​result,​displayName,​url] 
-</​code>​ 
-三個build的輸出結果如下,從結果內容不難得知個別資訊意義,需注意的是master的description會是null或master:​ 
-<​code>​ 
-{ 
-  "​builds":​ [ 
-  { 
-  "​description":​ "​origin/​integration_testing",​ 
-  "​displayName":​ "#​6611",​ 
-  "​result":​ "​SUCCESS",​ 
-  "​url":​ "​http://​tonylin.idv/​job/​Example/​6611/"​ 
-  }, 
-  { 
-  "​description":​ "​origin/​fix_memory_leak",​ 
-  "​displayName":​ "#​6610",​ 
-  "​result":​ "​SUCCESS",​ 
-  "​url":​ "​http://​tonylin.idv/​job/​Example/​6610/"​ 
-  }, 
-  { 
-  "​description":​ null, 
-  "​displayName":​ "#​6583",​ 
-  "​result":​ "​SUCCESS",​ 
-  "​url":​ "​http://​tonylin.idv/​job/​Example/​6583/"​ 
-  } 
-] 
-} 
-</​code>​ 
-==== 取得此build的artifact列表 ==== 
-從前一次query結果,以origin/​integration_testing為例,我們需要的build URL為: 
-<​code>​ 
-http://​tonylin.idv/​job/​Example/​6611/​ 
-</​code>​ 
-接著我們可以透過以下URL去query artifacts,我需要的是檔案名稱與檔案下載路徑:​ 
-<​code>​ 
-http://​tonylin.idv/​job/​Example/​6611/​api/​json?​tree=artifacts[fileName,​relativePath] 
-</​code>​ 
-可以看到結果如下:​ 
-<​code>​ 
-{ 
-  "​artifacts":​ [ 
-  { 
-  "​fileName":​ "​user_guide.pdf",​ 
-  "​relativePath":​ "​dist/​user_guide.pdf"​ 
-  }, 
-  { 
-  "​fileName":​ "​Example_1.0_build6611_linux_x64.bin",​ 
-  "​relativePath":​ "​dist/​Example_1.0_build6611_linux_x64.bin"​ 
-  }, 
-  { 
-  "​fileName":​ "​Example_1.0_build6611_windows_x64.exe",​ 
-  "​relativePath":​ "​dist/​Example_1.0_build6611_windows_x64.exe"​ 
-  } 
-  ] 
-} 
-</​code>​ 
-接著只要根據你需要的檔案名稱做過濾後,將relativePath串到build URL就可以拿到你想要的東西了。 
-===== Sample code ===== 
-針對以上過程,我用python寫了一隻範例程式給大家參考:​ 
-<code python> 
-import requests 
-import json 
-import platform 
- 
- 
-def find_latest_build(base_url,​ project_name,​ branch=None):​ 
-    query_url = base_url + project_name + "/​api/​json?​tree=builds[description,​result,​displayName,​url]"​ 
-    response = requests.get(query_url) 
-    if response.status_code != 200: 
-        raise RuntimeError("​request failed, status code=%d"​ % response.status_code) 
- 
-    json_object = json.loads(response.content) 
-    found_build = None 
-    for build in json_object["​builds"​]:​ 
-        if not branch and build["​description"​] == "​master":​ 
-            return build 
-        elif build["​description"​] == branch: 
-            return build 
-    return None 
- 
- 
-def find_installer(build_url,​ file_prefix):​ 
-    is_windows = platform.system() == "​Windows"​ 
-    ext = "​.exe"​ if is_windows else "​.bin"​ 
-    query_url = build_url + "​api/​json?​tree=artifacts[fileName,​relativePath]"​ 
- 
-    response = requests.get(query_url) 
-    if response.status_code != 200: 
-        raise RuntimeError("​request failed, status code=%d"​ % response.status_code) 
- 
-    json_object = json.loads(response.content) 
-    for artifact in json_object["​artifacts"​]:​ 
-        file_name = artifact["​fileName"​] 
-        if file_name.startswith(file_prefix) and file_name.endswith(ext):​ 
-            relative_path = artifact["​relativePath"​] 
-            return build_url + "​artifact/"​ + relative_path 
-    return None 
-</​code>​ 
-簡單的測試案例:​ 
-<code python> 
-from unittest import TestCase 
-from jenkins.utils import find_latest_build 
-from jenkins.utils import find_installer 
- 
- 
-class TestJenkinsUtils(TestCase):​ 
-    base_url = "​http://​tonylin.idv/​job/"​ 
-    project = "​Example"​ 
-    installer_prefix = "​Example"​ 
- 
-    def test_find_latest_master_build(self):​ 
-        latest_build = find_latest_build(TestJenkinsUtils.base_url,​ TestJenkinsUtils.project) 
-        self.assertTrue(latest_build["​url"​].startswith(TestJenkinsUtils.base_url)) 
-        self.assertIsNone(latest_build["​description"​]) 
-        self.assertIsNotNone(latest_build["​displayName"​]) 
-        self.assertEqual("​SUCCESS",​ latest_build["​result"​]) 
- 
-    def test_find_latest_branch_build(self):​ 
-        branch_name = "​origin/​integration_testing"​ 
- 
-        latest_build = find_latest_build(TestJenkinsUtils.base_url,​ TestJenkinsUtils.project,​ branch_name) 
-        self.assertTrue(latest_build["​url"​].startswith(TestJenkinsUtils.base_url)) 
-        self.assertEqual(branch_name,​ latest_build["​description"​]) 
-        self.assertIsNotNone(latest_build["​displayName"​]) 
-        self.assertEqual("​SUCCESS",​ latest_build["​result"​]) 
- 
-    def test_find_none_build(self):​ 
-        branch_name = "​origin/​none"​ 
- 
-        latest_build = find_latest_build(TestJenkinsUtils.base_url,​ TestJenkinsUtils.project,​ branch_name) 
-        self.assertIsNone(latest_build) 
- 
-    def test_find_build_with_invalid_url(self):​ 
-        branch_name = "​origin/​none"​ 
-        try: 
-            latest_build = find_latest_build(TestJenkinsUtils.base_url,​ "​InvalidProject",​ branch_name) 
-        except RuntimeError as e: 
-            self.assertEqual("​request failed, status code=404",​ e.message) 
- 
-    def test_find_installer(self):​ 
-        latest_build = find_latest_build(TestJenkinsUtils.base_url,​ TestJenkinsUtils.project) 
-        installer_url = find_installer(latest_build["​url"​],​ TestJenkinsUtils.installer_prefix) 
-        self.assertTrue(installer_url.startswith(TestJenkinsUtils.base_url) and installer_url.__contains__(TestJenkinsUtils.installer_prefix)) 
- 
-</​code>​ 
-\\ 
-友藏內心獨白:​ 純粹是為了練python而做的。 
-===== Reference ===== 
-  * [[http://​stackoverflow.com/​questions/​17236710/​jenkins-rest-api-using-tree-to-reference-specific-item-in-json-array|透過jenkins restapi with tree取得特定項目]] 
-  * [[https://​www.cloudbees.com/​blog/​taming-jenkins-json-api-depth-and-tree|Taming the Jenkins JSON API with Depth and "​Tree"​]] 
- 
-=====    ===== 
----- 
-\\ 
-~~DISQUS~~ 
-