發 npm 包對於稍微大點的廠來講都是個頻繁需求,所以本地執行計算版本命令以及 npm publish 都是不大可行的,大都會有一個單獨的部署系統去自動幫助咱們完成這個事情。
git
今天就來聊聊這個部署系統中核心的計算版本以及發佈的邏輯以及流程。正則表達式
聊部署系統以前,咱們先得來聊聊語義化版本,由於筆者發現不少人對於這一塊內容仍是隻知其一;不知其二。npm
版本中攜帶 alpha、beta、rc 等 tag 字樣,統稱先行版,通常格式爲 x.y.z-[tag].[次數 / meta 信息]json
通常的版本號格式都爲 X.Y.Z,分別的含義爲:ide
可是這個語義也不是一成不變的。好比當版本號爲測試版時(版本小於 1.0.0 時),咱們能夠將語義修改成 0.minor.patch。由於此時出現不兼容 API 是很正常的事情,不該該直接改動主版本號,而是應該改動次版本號,同時將功能新增及 bug 修復形成的版本變動體如今補丁上。工具
X.Y.Z 必須爲正整數且前面不能補零。測試
X.Y.Z 在每次變動版本號時,須要重置更小的版本號至 0。好比說 1.0.2 升級至 1.1.0。spa
同一個版本的先行版屢次發佈,只需變動末尾的次數或者 meta 值。好比說 1.0.0-beta.0 再次發佈先行版應爲 1.0.0-beta.1。翻譯
測試版通常從 0.1.0 開始計算。正式版通常在結束快速迭代以及開發者認爲 API 穩定之後就能夠發佈。orm
npm 項目分爲兩種包結構:
若是咱們須要實現自動發版,就得讓服務知道咱們究竟是須要發什麼版本,不然不管怎樣都不可能實現自動計算版本的需求。
所以咱們須要引入 commitizen 這個工具。
這個工具能夠幫忙咱們提交規範化的 commit 信息:
格式以下:
<type>[optional scope]: <description> [optional body] [optional footer(s)]
通常對於平常開發來講沒那麼嚴謹,type、description 必填,breaking 在須要的時候選擇,其餘內容無關緊要。
未免讀者不明白這三者分別表明什麼,筆者先來解釋下
type 就是本次 commit 所作的代碼變更,基本分爲如下幾種:
固然若是用戶有個性化需求的話,也是能夠增刪這部份內容的。
description 就是字面意思了,表明本地 commit 的信息。
最後是 breaking,當有不兼容的 API 出現時咱們須要提交這部分的內容,告知正式版須要變動主版本號。
PS:上文中說的都是正式版,若是當前版本爲測試版的話,變動版本規則參考 版本變動規則小節。
最後生成出來的內容大體長這個樣子:fix: do not alter attributes。
另外還有一個注意點是多包的問題。若是發版用統一版本的話事情就基本回歸到單包結構上了,很簡單。可是若是版本不統一的話,咱們就須要收集到底有哪些包是變動過文件的,在部署時只對變動過的包進行操做。
這裏大體有兩種方法能夠實現:
第一種方法是 @lerna/changed,這個工具能夠幫助咱們找到全部變動過的二方包。這裏原理其實挺簡單的,核心就是經過 git command 去實現:
git diff --name-only {git tag / commit sha} --{package path}
翻譯過來就是尋找從上次的 git tag 或者初次的 commit 信息中查找某個包是否存在文件變動。
第二種方式能夠改造 git cz 工具,新增一個功能:每次提交的時候自動帶上本次提交變動了哪些包,固然底下仍是用了上面的原理,可是咱們能夠根據需求來定製更多的功能,更自由。
規範化的 commit 信息是自動部署系統的基石,不管用工具也好仍是直接手寫,同時也能讓開發者清晰地瞭解大體項目作了哪些變動。
計算版本是個挺有趣的東西,這裏咱們須要用到 semver 來幫助咱們計算,固然多包場景下你也可使用 lerna 計算,可是咱們內部仍是直接統一都 semver 算了。
另外算版本這件事情須要分場景來論,接下來咱們一個個來看。
固然在開始以前,咱們須要瞭解下版本的通用變動規則,由於幾個場景都基於這個通用規則。
首先來介紹下升版本所須要用到的幾種類型:
major | minor | patch | premajor | preminor | prepatch | prerelease
前三種以前就聊過,這裏再也不多說。
以後三種都對應先行版,以 beta 版本舉例 premajor,能將版本 1.0.0 變動爲 2.0.0-beta.0,其實大致上仍是和前三者相同,無非多了一個先行版本號。
最後種一樣也是對應先行版。以 beta 版本舉例,能將版本 1.0.0 變動爲 1.0.1-beta.0,同時也能將版本 1.0.1-beta.0 變動爲 1.0.1-beta.1。
知道了變動版本類型,咱們就該想該如何得出它們了。通常來講用戶都會提交多個 commit,咱們首先須要找出其中全部的 commit type 而且取出一個最大值。
好比說用戶自上次發版以來共提交了三個 commit,類型分別爲 feat、doc、breakchange,那麼最大類型爲 breakchange。
得出最大 commit type 後,咱們須要根據不一樣的版原本計算。好比說正式版與測試版發版規則就不一樣,詳見 版本號格式,再也不贅述。
舉個例子,當前版本爲 1.0.0,此時根據 commit 咱們得出最大 type 爲 feat,且須要發佈先行版(beta),所以最終計算得出的變動規則爲 preminor,可將版本升級爲 1.1.0-beta.0。
上文有說到咱們須要分析 commit 來獲取 type,那麼讀者可能會疑問如何分析?
其實原理很簡單,仍是用到了 git command:
git log -E --format=%H=%B
對於以上 commit,咱們能夠經過執行命令得出如下結果:
固然這樣分析是把當前分支的全部 commit 都分析進去了,大部分發版時候咱們只須要分析上次發版至今的全部變動,所以須要修正 command 爲:
git log 上次的 commit id...HEAD -E --format=%H=%B
最後就是各類正則表達式大顯身手的時候了,想拿啥信息匹配就行。
單包場景實際上是最簡單的,直接套用通用變動邏輯就行。
單純的多包環境其實也是簡單的。無非比單包多了一步須要先找到哪些文件被變動了,而後須要篩選出 commit 中對應當前包的 type,最後就是套用通用變動邏輯。
先解釋下這個場景,好比說目前維護了 A、B、C 三個包,A 包的 dependencies 中包含了 B 和 C,這就是有依賴的意思,此時計算版本還須要多個步驟。
當通用邏輯結束之後,咱們須要根據依賴關係來判斷是否還須要變動包版本。
好比說本地提交須要執行 patch 變動 B 包版本,其它兩包都沒有代碼變更。可是實際上咱們還須要變更 A 的版本,不然光升 B 不升 A,用 A 包的用戶就用不到 B 包的新版本變化了。
當咱們將全部版本計算完畢之後,就須要寫入 package.json 而後 執行 npm publish,最後還須要提交下代碼打上 tag。
本篇文章就是大體聊了下算版本以及發佈這部分的內容,你們有問題的能夠交流討論。
另外我相信確定有讀者會說這作的太麻煩,有別的工具能夠簡化步驟。這個筆者固然也知道,可是他們底下自動修改版本的原理都是和本文一致的,瞭解下工具底下是怎麼作事的也不爲過。