自從去年用上了 Jenkins 進行 CI/CD 之后,工作效率高了不少,摸魚的時間更多了。不過 Jenkins 好是好,但在功夫網的影響下,插件就是經常更新不成功的,就像下面這樣子:
查了不少資料,絕大部分都說把升級站點改了就行
然而並沒有什么卵用,只是獲取插件列表從這個地方獲取而已,安裝/更新插件的時候該炸還是得炸。
作為一個有代碼潔癖的人,看着有插件更新不了那感覺就像有屎拉不出的難受。於是乎這幾個月以來一直是通過上面圖中的手動上傳插件來進行更新的。可是效率實在是低,一兩個插件還好,有時候一堆插件有更新,那一個個上傳是真的煩。
最近幾天又相對閑了點,察覺到 Jenkins 是有個 REST API 的,那么能不能通過程序化來解決問題呢。嘗試了下,算是有個比較滿意的解決方案了。
首先,要用 Jenkins REST API 是需要權限的,並不是說隨便來個人都可以調用。Jenkins REST API 是通過 token 進行驗證的。默認是沒有 token 的,需要手動添加。
登錄 Jenkins 管理面板,進入管理用戶
然后選擇一個用戶,點擊左側設置,然后添加 token 並且用你的小本本記錄下來
這樣就為這個用戶添加了一個 REST API 的 token 了,后續調用 REST API 帶上這個 token 就是了
以 C# 的 HttpClient 為例:
var httpClient = new HttpClient(); httpClient.SetBasicAuthentication("username", "apiToken");
這樣寫就行了,SetBasicAuthentication 方法來自 IdentityModel 這個 nuget 包。(https://www.nuget.org/packages/IdentityModel/)
接下來我們要先獲取哪些插件是有更新的。
在瀏覽器中來到 /pluginManager/api/ 這個頁面,點開 JSON API。
理論上會得到這么個 JSON:
一堆空白?再看一下文檔,加上 depth 參數就好了。加上 depth=1,再次請求 /pluginManager/api/json?pretty=true&depth=1
當前安裝的所有插件的信息都返回了。而且這里還返回了 hasUpdate 代表這個插件是否有更新。
用 C# 稍微建個模好了
public class JenkinsPlugin { [JsonProperty("hasUpdate")] public bool HasUpdate { get; set; } [JsonProperty("shortName")] public string ShortName { get; set; } [JsonProperty("url")] public string Url { get; set; } [JsonProperty("version")] public string Version { get; set; } }
接下來假如某個插件有更新的話,那么就下載這個插件的新版本好了,打開清華大學 Jenkins 的鏡像頁,並轉到插件目錄 https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/
以 git 插件為例,最新版本的下載地址如下:
https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/git/latest/git.hpi
也就是說某個插件的最新版本在清華大學鏡像站的下載地址是
https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/{plugin.shortName}/git/lastest/{plugin.shortName}.hpi
用 C# 擼個下載代碼好了:
public class TsinghuaClient { private static readonly HttpClient Client = new HttpClient(); public async Task<byte[]> DownloadPluginAsync(string pluginName) { var url = $"https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/{pluginName}/latest/{pluginName}.hpi"; var bytes = await Client.GetByteArrayAsync(url); return bytes; } }
接下來就是把這個傳到 Jenkins 上。
以 C# 代碼為例就是
using (var content = new MultipartFormDataContent()) { content.Add(new ByteArrayContent(plugin), "name", fileName);// plugin 為 byte[] var response = await client.PostAsync("/pluginManager/uploadPlugin", content); response.EnsureSuccessStatusCode(); }
上傳成功的話,狀態碼是 200 OK。
最后就是要讓 Jenkins 安裝新版本的插件了,這個只需要重啟一下 Jenkins 即可。在瀏覽器中打開 /api 路徑,並滾動到最底部
左邊那個是強制重啟,右邊那個是等待到沒任務時再重啟。我們用右邊那個。
代碼擼一下:
public async Task RestartAsync() { var response = await client.PostAsync("/safeRestart", null); Debug.Assert(response.StatusCode == HttpStatusCode.ServiceUnavailable); }
重啟指令發送成功后會返回 503 Service Unavailable 的。
總結一下流程就是:
獲取已安裝插件列表 –> 篩選有更新的插件 –> 到清華大學鏡像站下載插件最新版本 –> 上傳到 Jenkins –> 重啟 Jenkins
順手擼了個 WPF 的 app,也把源碼傳上來好了
https://files.cnblogs.com/files/h82258652/JenkinsUpdator.zip
使用的時候注意配置 app.config