從 Commit 規範化到發佈自定義 CHANGELOG 模版

前言

最近在學習 Git 提交規範、發佈及生成 CHANGELOG,最後實現本身的 CHANGELOG 模版併發布到 NPM,插件地址請戳這裏html

以前對 Git Commit 不是很規範,想到什麼提交什麼,團隊中每一個人的提交方式都不一樣,沒有很特別的指定哪些 commit 是新功能,哪些是修復 bug,查看 commit 記錄比較吃力前端

對版本的概念也不熟,使用 git tag 打版本以前,都須要先查一遍遠程上的版本是多少,新增完本地 tag 以後再將 tag push 到遠程倉庫,這也只是完成了打版本的步驟,若是須要提供 CHANGELOG.md 文件來講明每次版本的更新內容就比較麻煩vue

這時候就須要插件來幫咱們規範 git commit 提交、自動化發佈版本,自動生成 CHANGELOGnode

本文篇幅較長,圖片較多,提早預警!git

husky 鉤子插件

使用 husky 來管理 git commit 以前的操做,爲何要這麼作,由於咱們能夠在 git commit 以前再校驗一次代碼,防止提交「髒」代碼,保證代碼庫中的代碼是「乾淨」的,husky 不只僅能管理 commitgit 的鉤子幾乎都能管理,不過用的最多的仍是 commitpushgithub

  • 安裝
npm install husky --save-dev
複製代碼
  • 在 package 中配置
"husky": {
  "hooks": {
    "pre-commit": "npm run lint"
  }
}
複製代碼

這裏在 commit 以前,咱們先執行了 npm run lint,這是 vue-cli3 給咱們提供的命令,會根據咱們的 eslint 規則來校驗代碼,而且自動修復,記得先 git add 文件vue-cli

  • 使用

但這樣會有一個問題,就是此次提交,我可能只修改了一個文件,好比我就修改了 a.js 的內容,但它依然會校驗 src 下面全部的 .js 文件,很是的不友好。npm

致使的問題就是:每次提交代碼,不管改動多少,都會檢查整個項目下的文件,當項目大了以後,檢查速度也會變得愈來愈json

lint-staged

解決上面的痛點就須要使用 lint-staged。它只會校驗你提交或者說你修改的部分內容。gulp

npm install lint-staged -D -S

修改 package.json 配置:

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "src/*_/_.{js,vue}": ["npm run lint", "git add"]
  }
}
複製代碼

如上配置,每次它只會在你本地 commit 以前,校驗你提交的內容是否符合你本地配置eslint 規則,若是符合規則,則會提交成功。若是不符合它會自動執行 npm run lint 嘗試幫你自動修復,若是修復成功則會幫你把修復好的代碼提交,若是失敗,則會提示你錯誤,讓你修好這個錯誤以後才能容許你提交代碼。

但這並非強制的,有些團隊成員或者說剛來的新人沒有在編輯器中配置或者無視命令行中提示的錯誤,強行提交,這時候就須要配置 pre-commit 這種強制性校驗的東西,保證全部提交到遠程倉庫的內容都是符合團隊規範的。

參考花褲衩大佬的文檔 vue-element-admin

Commit 提交規範檢查

在多人協做項目中,若是代碼風格統1、代碼提交信息的說明準確,在後期維護以及 Bug 處理時會更加方便。

Git 每次提交代碼,都要寫 Commit message(提交說明)

可是每一個人的提交方式不一樣,沒有很特別的指定哪些 commit 是新功能,哪些是修復 bug,這時須要插件來幫咱們規範化

規範 Commit message 的做用

  • 提供更多的歷史信息,方便快速瀏覽
  • 過濾某些 commit(好比文檔改動),便於快速查找信息
  • 直接從 commit 生成 CHANGELOG
  • 可讀性好,清晰,沒必要深刻看代碼便可瞭解當前 commit 的做用。
  • 爲 Code Reviewing(代碼審查)作準備
  • 方便跟蹤工程歷史

在項目中安裝插件:

npm i commitizen cz-conventional-changelog --save-dev
複製代碼
  • 在 package 中配置
"config": {
  "commitizen": {
    "path": "cz-conventional-changelog"
  }
}
複製代碼
  • 在 package 的 scripts 中配置命令
"commit": "git-cz",
複製代碼
  • 使用

依賴安裝完就能夠開始秀操做

要先 git add . 將文件加入本地暫存區後,才能 commit

npm run commit
複製代碼

注意,若是以前經過 git commit 這種方式提交代碼,都要改成 git-cz

注意,若是以前經過 git commit 這種方式提交代碼,都要改成 git-cz

注意,若是以前經過 git commit 這種方式提交代碼,都要改成 git-cz

Commit message 格式說明

Commit message 通常包括三部分:HeaderBodyFooter

Header type(scope):subject type(必需)、scope(可選) 和 subject(必需)

這裏有幾種類型能夠選擇

type:用於說明 commit 的類別,規定爲以下幾種

feat:新功能
fix:修補 bug
docs:修改文檔,好比 README, CHANGELOG, CONTRIBUTE 等等
style: 不改變代碼邏輯 (僅僅修改了空格、格式縮進、逗號等等)
refactor:重構(既不修復錯誤也不添加功能)
perf: 優化相關,好比提高性能、體驗
test:增長測試,包括單元測試、集成測試等
build: 構建系統或外部依賴項的更改
ci:自動化流程配置或腳本修改
chore: 非 src 和 test 的修改
revert: 恢復先前的提交
複製代碼

scope:(可選)用於說明 commit 影響的範圍

subject:commit 的簡要說明,儘可能簡短

Body

Body 部分是對本次 commit 的詳細描述,能夠分紅多行

Footer

Footer 部分只用於兩種狀況。

  • 不兼容變更

若是當前代碼與上一個版本不兼容,則 Footer 部分以 BREAKING CHANGE 開頭,後面是對變更的描述、以及變更理由和遷移方法。

  • 關閉 Issue

若是當前 commit 針對某個 issue,那麼能夠在 Footer 部分關閉這個 issue, 也能夠一次關閉多個 issue

? Select the **type** of change that you're committing:
(type) 選擇提交更改的類型
? What is the **scope** of this change (e.g. component or file name)? (press enter to skip)
(scope) 這次更改的範圍是什麼(組件或者文件名)
? Write a **short**, imperative tense description of the change:
(subject) 寫一個簡短的,命令式的變化描述
? Provide a **longer description** of the change: (press enter to skip)
(Body) 提供更改的長描述
? Are there any **breaking changes**?
(Footer) 有沒有突破性的變化
? Does this change affect any open **issues**? (y/N)
(Footer) 這次更改是否有要關閉 issues
複製代碼

若是當前 commit 針對某個 issues

? Does this change affect any open issues? (y/N)

選擇 Y,輸入 Closes #1 (表示關閉第 1 個 issues)

也能夠一次關閉多個 issues : Closes #1 #2 #3

CHANGELOG 中 issues 默認的連接地址是根據 package.json 中的 repository 來生成的

若是 repository 沒有,則會獲取 git 中的遠程倉庫路徑來做爲前綴

以後就會進行代碼格式化校驗,若是代碼不符合規範,一樣會提交失敗,必定要確保項目當前格式沒問題,規範後再提交!!!

更多細節能夠參考阮一峯老師的博客:Commit message 和 Change log 編寫指南

自動發佈版本

這裏我使用 release-it 做爲發佈版本插件,也能夠選擇 standard-version

  • 安裝插件
npm install --save-dev release-it
複製代碼
  • 在 package 的 scripts 中配置命令
"release": "release-it"
複製代碼

在項目終端輸入 npm run release 就會執行操做

若是出現下圖的報錯信息,能夠經過登陸 npm 解決

在發佈版本前,必定確認是否還有文件沒有提交,不然是會報錯的,報錯信息以下:

ERROR Working dir must be clean.
Please stage and commit your changes.
Alternatively, use `--no-git.requireCleanWorkingDir` to include the changes in the release commit (or save `"git.requireCleanWorkingDir": false` in the configuration).
複製代碼

工做目錄必須是乾淨的,請暫存 (add) 並提交 (commit) 你的更改

不推薦經過修改 git 配置來解決,由於發佈一個版本就應該是沒有任何更改的,穩定的纔去發佈,git tag 若是沒有指定對應的 commitID,默認最新的 commit 上打標籤,注意!!要在主分支(master)上發版本

release-it會讀取本地package.json 中的 version,提示你當前版本是多少,不須要開發者使用 git tag -l 來查詢當前本地版本是多少,以及這個版本作了哪些改動,它提供了幾個默認選項讓你選擇版本號

若是你以爲上面的選項不能知足你的要求,最後一個選項是本身填入版本信息(要符合規範),有關版本規範能夠參考語義化版本 2.0.0

確認版本後,會自動修改 package.json 的版本信息,這是前端開發者查看當前項目版本的途徑之一。以後就是詢問是否要 commit,是否打 tag,是否 push 到遠程倉庫,能夠一路回車。最後一項若是是公司項目,不須要上傳到 npm 倉庫,選 NO 便可,即便選了 Yes,但只要你在 package.json 中配置 privatetrue,也不會上傳。如何查看發佈成功? 能夠輸入 git tag -l 查看本地 tag,也能夠 git ls-remote --tags origin 查看遠程 tag

可是這只是一個 tag,沒有詳細信息,更新日誌仍是須要開發者手動編寫

這個時候就須要用到自動生成 CHANGELOG 插件了

自動生成 CHANGELOG

安裝

npm i conventional-changelog-cli --save-dev
複製代碼

配置 package.json

"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
複製代碼

上面 changelog 命令不會覆蓋之前的 CHANGELOG,只會在 CHANGELOG.md頭部加上自從上次發佈以來的變更。

npm run changelog
複製代碼

生成 CHANGELOG.md 文件

CHANGELOG.md 的頭部加上自從上次發佈版本以來的變更。顯示 feat、bug、doc 等類型

生成的 CHANGELOG 不會按 commit 上傳的時間順序排序,有人給官方提交了 issues,等待官方解決。。👉傳送門

能夠打開 GitHub/GitLub 倉庫,將更新日誌生成的內容對應的填入 tag 版本中就能夠了

深刻 conventional-changelog 源碼

這裏先展現最終生成的 CHANGELOG 效果圖

起源背景以下:

測試:」須要在 CHANGELOG 中生成 commit 對應的提交人,這樣問題定位就知道去找誰負責」

我:「😎 這個簡單~配置下參數就能夠了」

我覺得只要配置一下參數,畢竟 CHANGELOG 插件是支持自定義參數的,當我看到文檔懵逼了,沒有提供這兩個參數,顯示提交人和提交人郵箱,咋辦,翻 issue。。。這個需求應該有人提 😏,根據 #351 知道了使用自定義配置須要從外部傳入自定義配置文件

新建一個配置文件,在命令後面帶上 -n <文件路徑>

{
  "scripts": {
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 -n ./changelog-option/index.js"
  }
}
複製代碼

解決了使用自定義配置問題,如何增長 CHANGELOG 生成更多的提交信息,仍是翻 issue... #349

結合起來大概是這樣,試試效果:

format 裏面有 authorName 和 authorEmail 字段,運行 npm run changelog 後依舊沒有效果 😖 只能翻源碼了

VSCode 調試 node_modules 第三方插件

配置 launch.json,調試 conventional-changelog-cli 插件下的 cli.js 文件,這裏保持和 package 中的 changelog 一致,傳入參數 "-p", "angular", "-i", "CHANGELOG.md", "-s", "-r", "0", "-n", "./changelog-option/index.js"

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "cwd": "${workspaceFolder}",
      "program": "${workspaceFolder}\\node_modules\\conventional-changelog-cli\\cli.js",
      "args": [
        "-p",
        "angular",
        "-i",
        "CHANGELOG.md",
        "-s",
        "-r",
        "0",
        "-n",
        "./changelog-option/index.js"
      ]
    }
  ]
}
複製代碼

全局搜索傳入的配置項字段:gitRawCommitsOpts,打個斷點調試一下

發現做者是將用戶傳入的 gitRawCommitsOpts 作個合併,最後傳入到 conventionalChangelog 方法中去執行,繼續查看該方法

插件由 conventional-changelog-cli 跳轉到 conventional-changelog

判斷用戶是否有傳入 preset 預設參數,調試的時候使用了 angular 的配置 (-p angular)

這裏 return 了一個 conventionalChangelogCore 方法,依舊點擊跳轉

conventional-changelog-core

做爲插件的核心庫,最核心的地方就是 mergeConfig 這個方法

在 core 中將配置傳入 mergeConfig 中進行合併

format 默認只有 hashgitTagscommitterDate,沒有須要的 authorNameauthorEmail,fromTag 是咱們最後一次提交的 tag,merges: false 表示在 CHANGELOG 中不會生成 merges 分支的信息

mergeConfig 是一個 Promise,求值後將配置傳給了 gitRawCommits,涉及了 pipe 導流來傳遞數據

gitRawCommitsOpts 配置傳入 gitRawCommits 方法中,繼續點進去看,又會跳轉到 git-raw-commits 插件

git-raw-commits

經過 git-raw-commits 的 GitHub 官網 README,發現這個插件是從本地 git 倉庫中獲取提交記錄,以前傳入的 format 就是 git-log 中的參數

hash:哈希值

gitTags:標籤

committerDate:提交時間

authorName:提交人

authorEmail:郵箱
複製代碼

更多 git-log 細節能夠去看 git 官方文檔,也能夠在 git log 後面帶上咱們配置的 format 進行格式化

直接使用 git log 查看 git 提交記錄中,也有 Author 的 name 和 email 字段

看到這裏,肯定了 git-raw-commits 插件只是從 git 中讀取數據並格式化,那麼確定有個插件是將這些數據寫成 CHANGELOG.md 文件,因而繼續翻 conventional-changelog-core ,發現 conventional-changelog-writer,這個插件先不看,還記得以前使用的是 angular 的預設嗎,能夠去看 conventional-changelog-angular 插件

好的項目從文件名就知道各個文件是作什麼的,將不一樣插件的配置單獨拆分,這點值得學習

conventional-changelog-angular

writer-opts.js 就是寫入 CHANGELOG 的配置,最後會將配置傳給 conventional-changelog-writer,這裏來匹配咱們以前 commit message 的信息

其實在 writer 以前,還有一個 parser 插件,用來解析咱們提交的信息,這個 changelog 裏面究竟是依賴了多少插件。。。

在用 commit 規範化插件提交的時候,就須要填寫相應的信息,這裏打印一下 commit 信息

發現的確有 authorNameauthorEmail 這兩個字段存在,並且 conventional-changelog-writer這個插件就是將這樣的對象生成 CHANGELOG.md,經過插件的 README 能夠知道

如今字段也有了,可是爲何不會顯示呢,繼續看源碼,這裏用到了 templates/commit.hbs 文件

看到這裏也就差很少了,template 文件夾下就是生成 CHANGELOG 的模版文件,查了下 hbs(Handlebars) 是一個模版引擎。不過在 commit.hbs 中卻並沒有發現有用到這兩個字段,想一想也是,這兩個字段是我配置 gitRawCommitsOpts 傳入的

說明 angular 預設一開始就沒想過要生成 authorName 和 email。。。這就尷尬了,只能本身加上了,照葫蘆畫瓢,修改 commit.hbs 文件,在生成 commit 的 hash 值後面加上

成功啦~~!!!🎉🎉🎉

讓我激動一下,可是轉念一想 🤔,這種直接修改 node_modules 裏插件的源碼,根本無法分享啊,若是同事要用,不可能也這樣去修改 conventional-changelog-angular 的源碼吧,並且只要從新 npm install 安裝依賴後,以前修改了也會消失

做者已經在 conventional-changelog-cli 中提供了自定義的例子

不過這個地址已經被廢棄了,新地址就是咱們以前使用的 angular 預設 conventional-changelog-angular ,官方也有提供其餘預設模版,如:atomeslintjQuery

這種在一個 package 中管理多個項目是用了 lerna,一個用於管理擁有多個包的 JavaScript 項目的工具。是一種比較流行的 monorepo 項目管理模式,React、Vue、Babel 都有用這種模式來管理。

前面也分析了 conventional-changelog-angular ,直接 clone 源碼來改,建立 git-raw-commit.js

module.exports = {
  format:
    '%B%n-hash-%n%H%n-gitTags-%n%d%n-committerDate-%n%ci%n-authorName-%n%an%n-authorEmail-%n%ae'
}
複製代碼

在 index.js 中傳入並使用

'use strict'
const Q = require(`q`)
const conventionalChangelog = require(`./conventional-changelog`)
const parserOpts = require(`./parser-opts`)
const recommendedBumpOpts = require(`./conventional-recommended-bump`)
const writerOpts = require(`./writer-opts`)
// 格式化 git log 信息
const gitRawCommitsOpts = require('./git-raw-commit')

module.exports = Q.all([
  conventionalChangelog,
  parserOpts,
  recommendedBumpOpts,
  writerOpts,
  gitRawCommitsOpts
]).spread(
  (
    conventionalChangelog,
    parserOpts,
    recommendedBumpOpts,
    writerOpts,
    gitRawCommitsOpts
  ) => {
    return {
      conventionalChangelog,
      parserOpts,
      recommendedBumpOpts,
      writerOpts,
      gitRawCommitsOpts // 傳入
    }
  }
)
複製代碼

以後修改 commit.hbs,顯示 authorName 和 authorEmail

這裏有個小坑!!我用 VSCode 修改完直接保存後,若是有屢次提交,不會折行,會擠在同一行,估計是保存的格式不對,也許是我 VSCode 安裝了比較多的格式化擴展,建議用 Notepad++ 去修改 commit.hbs 文件

替換 issues 路徑

公司使用 redmine 來管理項目,測試人員會在 redmine 中提 issues,這裏生成完 CHANGELOG 要批量替換 issues 的地址,將 GitLab 地址前綴替換成 redmine,網上說用 replace 庫,可我發現這個庫上傳 npm 是三年前,而且已經不維護了,使用後也報錯。。。因而寫了一個簡單的字符串替換文件,生成完 CHANGELOG 後運行該文件便可替換,支持傳遞參數(參考 conventional-changelog 源碼,使用了 minimist 插件來獲取傳遞的參數)

{
  "scripts": {
    "changeissueurl": "node ./changelog-option/replace.js https://gitlba.com/issues/ https://redmine.example.com/issues"
  }
}
複製代碼

再把這兩個腳本集成到一個 version 中,以後要發版本,生成 CHANGELOG 只要運行 npm run version 便可

發佈到 NPM 倉庫

這樣仍是太麻煩,對於使用者來講不須要了解太多,並且文件存在本地,不方便遷移,🤔 能不能像 angular 同樣直接作成預設模版,讓 conventional-changelog 直接去用咱們自定義的預設模版就好了,爲了驗證,仍是得翻源碼,以前有調試到,可是沒細看

conventional-changelog-preset-loader

預設只要按照 ${scope}conventional-changelog-${name} 這種命名規範就能夠被 require,scope 是由於 npm 倉庫不能同名,能夠加上本身的用戶名做爲做用域,例如:@zsh/conventional-changelog-angular,以後在配置中改成 -p @zsh/angular 就可使用自定義的預設了

感謝 conventional-changelog !很少說,起一個 npm 項目,將以前的文件都放進去,再次對模版進行優化。

TODO:

  • authorName 和 authorEmail 不必定是必需的,可配置
  • issues 替換地址更爲簡便
  • 給 Title 新增 emojis 🚀

由於這裏獲取的 commit 是字符串格式,能夠在 commit.hbs 模版中設置一個值,以後再根據用戶的配置來進行替換,這樣 authorName 和 authorEmail 就不是必需的,默認禁用,須要手動設置開啓

issues 和 emojis 比較簡單就不說了,相信你們若是認真的看到這裏,徹底能夠作你本身的預設~

因爲是第一次發佈到 npm 上,沒什麼經驗,效果很差還望見諒 🏃‍♂️,npm 地址:conventional-changelog-custom-config

使用

npm install conventional-changelog-custom-config --save-dev
複製代碼

經過在 package.json 中配置參數的形式來定製 CHANGELOG,不填配置則會按照 angular 的預設模版生成 CHANGELOG,具體配置以下:

{
  "scripts": {
    "changelog": "conventional-changelog -p custom-config -i CHANGELOG.md -s -r 0"
  },
  "changelog": {
    "bugsUrl": "https://redmine.example.com/issues/",
    "emojis": true,
    "authorName": true,
    "authorEmail": true
  }
}
複製代碼

bugsUrl

Type: string Default: false

當你須要將 issues URL 替換成其餘 URL 時,使用該參數,例如使用 redmine 管理項目, bugsUrl: 'https://redmine.example.com/issues/'

若是不填 bugsUrl 則會根據 package.json 中的 repositoryrepository.url 來做爲 issues URL

{
  "repository": {
    "type": "git",
    "url": "https://github.com/example"
  }
}
複製代碼

若是 repository.url 也沒有,則會獲取 git 中的遠程倉庫路徑來做爲前綴,conventional-changelog-core 源碼地址

若是你使用了第三方的協做系統(例如 bitbucket), 推薦你使用這個插件 conventional-changelog-angular-bitbucket

emojis

Type: boolean Default: false,emojis types 參考 gitmoji

Commit Type Title Description Emojis
feat Features A new feature
fix Bug Fixes A bug Fix 🐛
docs Documentation Documentation only changes 📝
style Styles Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) 💄
refactor Code Refactoring A code change that neither fixes a bug nor adds a feature ♻️
perf Performance Improvements A code change that improves performance ⚡️
test Tests Adding missing tests or correcting existing tests
build Build Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) 👷
ci Continuous Integrations Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) 🔧
chore Chores Other changes that don't modify src or test files 🎫
revert Reverts Reverts a previous commit

authorName

Type: boolean Default: false

在 CHANGELOG 中生成用戶名

authorEmail

Type: boolean Default: false

在 CHANGELOG 中生成郵箱

更多節能夠看 README,碼字不易,開源不易,以爲不錯點給個 ⭐️ 吧~😝 感謝感謝~

總結

總結這一整套折騰過程,代碼風格規範 ----> commit 規範 ----> version 規範 ----> 生成 CHANGELOG ---> 自定義 CHANGELOG ---> NPM 發佈預設

前四個步驟看看 README 就直接上手,沒什麼難點,自定義 CHANGELOG 稍微麻煩些,對外開放 conventional-changelog-cli 收集用戶配置,如 -p angular -s -r 0 -n config.js,若是有預設模版,好比 angular,就將 conventional-changelog-angular 中的配置傳入 conventional-changelog-core 中 merge,以後經過 git-raw-commits 從本地 git 中獲取 log 數據,conventional-changelog-parser 來解析用戶提交的信息,將兩種數據整合成一個對象,傳入 conventional-changelog-writer 生成 CHANGELOG.md 文件

剛開始安裝插件比較多,一旦配完就是一兩個命令的事,感興趣的也參照我這篇文章,本身寫一套模版用, npm 上也有不少預設模版能夠用,axetroy 大佬寫了個 VSCode 擴展 列入了 conventional-changelog 官方推薦 ,文章位置,人也在掘金 😏

本文篇幅較長,不免會有錯誤和不足的地方,但願大佬們留言指正,以避免誤人

參考文檔

git commit 、CHANGELOG 和版本發佈的標準自動化

Commit message 和 Change log 編寫指南

conventional-changelog-core

git-log

package.json

vue-element-admin

VSCode Debugging

相關文章
相關標籤/搜索