前言

當你的專案要升級套件時你是怎麼做的呢?打開你的 Visual Studio 然後再選擇 Nuget Package Manager 然後在 console 中去執行指令更新嗎?不論版本是否只是 patch 類型的微升級還是跳一個 major 的大改版都這樣做嗎?

安裝

在安裝之前這個工具會需要你先安裝 .NET Core 2.1 或更新的版本 若還沒有安裝的話可以先到這裡把所需要的環境先裝好。

安裝的指令相當簡單:dotnet tool install nukeeper --global,而更新的

install

使用檢查模式

藉由開啟這麼模式可以先讓你看看有哪些套件是可以進行升級

cd {your_repo_dir}

nukeeper inspect

或是

nukeeper inspect {your_repo_dir}

inspect mode

從這邊可以看出它不只可以幫你查出有哪些套件可以進行升級,還可以看出到底距離這些版本你 delay 了多久。

直接更新專案的套件

cd {your_repo_dir}

nukeeper update

同樣,另一種方式也是類似的

nukeeper update {your_repo_dir}

當然,若你覺得某一些套件更動實在影響太大,你可以用 exclude 參數來跳過這些套件

nukeeper update {your_repo_dir} --exclude {package_name}

而這個參數是可以接受簡單的 regex 判斷的,像是這樣用:

nukeeper update {your_repo_dir} --exclude ^AWSSDK.

上述的更新就可以將 AWSSDK. 開頭的套件給排除在外,就不用擔心一口氣將太多第三方的套件更新,讓測試範圍暴增。

exclude 就會有 include 而用法也是類似的

nukeeper update {your_repo_dir} --include ^AWSSDK.

這個參數也是可以接受一些簡易的 regex 來做篩選,而若你需要接上多個套件的話可以用以下的方式

nukeeper update {your_repo_dir} --include (^AWSSDK.^|Microsoft)

要注意的是,因為命令列下 | 是 pipe command 的方式,所以前面需要加上 ^ 來跳脫,另外不論是 include 或是 exclude 它預設接在後面的都會是用包含的概念來搜尋,也就是說上述的指令會去找 AWSSDK. 開頭或是名稱有 Microsoft 字樣的套件去更新。

另外若是在 Windows 環境使用 Powershell 的話需要調整一下寫法,調整如下

nukeeper update {your_repo_dir} --include '(^AWSSDK.|Microsoft)'

也就是用 ' 將參數的內容包覆起來,同時將跳脫使用的 ^

update include

這邊故意將其中一個套件的名稱打錯,可以發現若找不到的話就會直接忽略。另外,這邊也可以發現明明 AWSSDK. 開頭的套件有抓出兩個卻只有一個更新了,不過可以看看 AWSSDK 的套件命名並非標準的版本命名,其中 Polly 的版本號只有最後一號不同,而 Core 的版本號則是 patch 就不同了,而依據該工具更新的原則它只會比較到 patch 所以更後面的它就會無視。

限制更新的程度

若這個工具只能做到上述的地步那使用的情境還算有限,所以他有一個很貼心的設計,你可以決定套件更新的程度是要追到最新,還是只更新到新的版本小號就好。

nukeeper update --change minor

這個參數共有三個選項(major, minor, patch

假設:若有一個套件在專案中是 1.2.1 而目前最新的版本號到 3.1.2,若限制在 patch 的話,更新就會往 1.2.x (x > 1) 的方向來更新。若限制在 minor 的話就會看 1.x.y 的 x 最高會到哪裡,而 y 就會看最新到那一版,至於 major 則是預設的限制,它會去找最新的版本號。

但厲害的不只如此,剛剛從 inspect 指令中我們可以得到最新的版本號之外,我們還可以知道目前距離新版的時間差距。是的,它還可以用時間差距來做更新限制。

nukeeper update --age 6w

這指令表示套件將會用可取得時間 6 週或以上的可更新版本來做更新,時間單位除了 w (週),還有 d (日), h (小時)還有直接寫 0 不帶單位的方式,還表示只要套件有新版就會直接更新。

這個時間的限制條件可以讓你更新使用預設狀態下更新不了的套件,像是例子中的 Polly 套件

nukeeper update --age 0 --include ^AWSSDK.

update age

設定套件來源

是的,除了一般把套件放在公開的 nuget server 一定也會有讀取私有 nuget server 的需求,這個工具同樣也提供方法設定

nukeeper update --source https://api.nuget.org/v3/index.json --source {your_nuget_server}

一些小細節

若你有很多需要更新時你會發現它可能沒有把所有可以更新的套件都更新,這是因為若沒有給予 MaxPackageUpdates 參數的話,他的預設就會是 1,底下節錄一段這個邏輯的關鍵 code snippet (節錄自:UpdateCommand.cs)

1
2
3
4
5
6
7
const int defaultMaxPackageUpdates = 1;
var fileSettings = FileSettingsCache.GetSettings();

var maxUpdates = Concat.FirstValue(
                MaxPackageUpdates,
                fileSettings.MaxPackageUpdates,
                defaultMaxPackageUpdates);

而這個數值會用在套用 Filter 後剩下來的 packages 中。以下是關鍵的 code snippet (節錄自:UpdateSelection.cs)

1
2
3
4
5
var filtered = await ApplyFilters(candidates, remoteCheck);

var capped = filtered
             .Take(settings.MaxPackageUpdates)
             .ToList();

這個參數是用 Int32 這個資料型態去接的,另外程式裡面會判斷是否小於 1,所以基本上接受的數字就是 1 ~ Int32.MaxValue

它還能更有用嗎

唔~看到這邊你會許會想:恩,對,有它好像不錯,但是好像也沒差太多。

恩…那我換個方式來講好了

想法一

假想一下以下的情境:你有一個專案正在執行,你知道這個專案的套件已經很舊又很久了,你想要更新一下套件,但不想一口氣跳數個 major 版本號,甚至你不想跳 major 版本號,因為非常有可能有 breaking change 讓你既有的系統完全跑不動,你可能只是想將能更新的最小版本號 patch 給更新而已。難道要開啟內建的方式一個一個的更新?這樣太不人性化了。難道要讓一個人去做這件事?這樣太壓榨了。

何不把這個工具裝在 CI Server 上讓建制時去幫你做這件事情呢?既省時又不壓榨。

至於 major 版本號的更新則可以另外評估,或補上一些測試讓更新後的檢查更全面,時時更新,常保年輕,這樣你的專案就不會老到不敢更新了~

想法二

在沒有任何額外確認的情況下自動更新實在太嚇人了,但是拿來自動確認專案使用的套件是否已經太久沒有更新並做提醒依然是個不錯的使用方式,那麼你可以在 CI Server 上定期去跑一個 Job 讓它去檢查專案所使用的套件的狀態,並將結果送到 Slack, HipChat 等群聊軟體也是不錯的方式。

參考資料