本文主要解决以下问题:
- 如何在代码提交时进行代码规范检查(lint-staged)?
- 如何使用工具生成符合Angular commit规范的message?
- 如何通过gitHooks验证message是否符合规范?
- 如何使用工具自动生成changelog? 此文对应的github代码仓库:github.com/eyunhua/cod…
如果你想了解更详细的过程,请认真往下阅读;如果你想快速查看如何使用,请看『总结』目录。
前言
在一个多人协作的项目中,简洁清晰易懂的代码提交注释是能够快速定位问题的有效方式。commit message应该说明本次提交的目的。
对比下面这两张代码提交commit log图:
第一张:message没有实际的意义,看不出来本次提交改动的范围。
第二张:message简洁清晰易懂,可以看出当前是新增功能、修复问题等,并可看出此次提交影响的范围。
通过上面两张图可以看出,message写的符合规范是多么的重要!
那我们在日常工作中,仅仅通过人工去输入message,无法完全保证message提交的规范性。
接下来介绍一种社区比较流行的规范Angular 规范,并且通过工具去生成符合这种规范的message信息。
Angular commit规范
规范格式概览
<type>(<scope>): <subject> #header部分
// 空一行
<body>
// 空一行
<footer>
Header 是必需的,Body 和 Footer 可以省略。
规范格式详解
Header
Header部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。
type
用于说明本次commit的类型 只允许使用下面7个标识
- feat:新功能(feature)
- fix:修补bug
- docs:文档(documentation)
- style: 格式(不影响代码运行的变动)
- refactor:重构(即不是新增功能,也不是修改bug的代码变动)
- perf: 性能提升(提高性能的代码改动)
- test:测试
- build:构建过程或辅助工具的变动(webpack等)
- ci:更改CI配置文件和脚本
- chore:不修改src或测试文件的其他更改
- revert:撤退之前的commit
如果type为feat、fix、perf、revert,则该 commit 将肯定出现在 Change log 之中。其他情况(docs、chore、style、test)由你决定,要不要放入 Change log,建议是不要。
scope
用于说明本次commit影响的范围,比如首页、详情页等。
subject
用于说明本次commit的简短描述,不超过50个字符。
Body
用于本次commit的详细描述,可以分成多行 举例(实际应用应说明具体改动):
more info...
- first changes...
- second changes...
Footer
只用于下面两种情况
不兼容变动
如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。
举例:
vue-next changelog.md:github.com/vuejs/vue-n…
BREAKING CHANGE: `getTextMode` compiler option signature has changed from
``ts
(tag: string, ns: string, parent: ElementNode | undefined) => TextModes
``
to
``ts
(node: ElementNode, parent: ElementNode | undefined) => TextModes
``
关闭Issue
如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue 。
Closes #123, #234
Revert(可忽视)
还有一种特殊情况,如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header。
revert: feat(pencil): add 'graphiteWidth' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
Body部分的格式是固定的,必须写成This reverts commit .,其中的hash是被撤销 commit 的 SHA 标识符。
如果当前 commit 与被撤销的 commit,在同一个发布(release)里面,那么它们都不会出现在 Change log 里面。如果两者在不同的发布,那么当前 commit,会出现在 Change log 的Reverts小标题下面。
代码规范检查:lint-staged
检测暂存区的代码是否符合规范
介绍
在代码提交之前,进行代码规则检查能够确保进入git
库的代码都是符合代码规则的。但是整个项目上运行lint
速度会很慢,lint-staged
能够让lint
只检测暂存区的文件,所以速度很快。
Install
npx mrm@2 lint-staged
此命令将根据项目的package.json
依赖项中的代码质量工具安装和配置husky
和lint staged
,因此,请确保在此之前安装(npm install—save dev)并配置所有代码质量工具,如Prettier
和ESLint
。
运行完上述命令后,将会在package.json
中出现:
"lint-staged": {
"*.{js,vue}": [ // 对不同的后缀文件,运行不同的检查命令
"vue-cli-service lint",
"git add"
],
"*.{ts}": [ // 对不同的后缀文件,运行不同的检查命令
"xxx"
]
}
husky中使用
在.husky
目录下的pre-commit
钩子脚本中,添加如下脚本:
npx lint-staged
yorkie中使用
在package.json
中,添加如下脚本:
{
"gitHooks": {
"pre-commit": "lint-staged"
}
}
配置完脚本后,在我们执行git commit -m 'xxx'
提交代码时,就会自动触发pre-commit
钩子进行代码规范检查。
commit-msg检查方式一:脚本
package.json
文件:
"gitHooks": {
"commit-msg": "node build/verify-commit-msg.js"
}
build/verify-commit-msg.js
文件:
返回非0值则退出
/* eslint-disable */
const chalk = require("chalk");
const msgPath = process.env.GIT_PARAMS;
const msg = require("fs")
.readFileSync(msgPath, "utf-8")
.trim();
// ([A-Za-z0-9]+-[A-Za-z0-9]+)+
const commitRE = /^(build|chore|ci|docs|feat|fix|wip|perf|refactor|revert|style|test|temp|)(\(.+\))?: .{1,50}/;
if (!(commitRE.test(msg) || msg.indexOf("Merge") === 0)) {
console.error(
` ${chalk.bgRed.white(" ERROR ")}
[${chalk.red(msg)}] 是 ${chalk.red("无效的提交消息格式")}
${chalk.red("自动生成更新日志需要正确的提交消息格式 例如:")}
${chalk.green("issue-1 feat(模块): 预发布环境增加 A 模块")}
${chalk.green("issue-2 fix(文案): 修复错误文案")}`
);
process.exit(1); // 返回非0值得退出
}
/* eslint-enable */
commit-msg检查方式二:commitlint
检查
git commit -m 'xxx'
的message是否符合规范
Install
项目内安装@commitlint/cli
、@commitlint/config-conventional
:
npm install --save-dev @commitlint/cli @commitlint/config-conventional
Configure
可以在commitlint.config.js
、.commitlintrc.js
、.commitlintrc.json
或.commitlintrc.yml
文件或package.json
中的commitlint
字段中定义配置。
当前以commitlint.config.js
为例:
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
在husky中使用
添加.husky/commit-msg
钩子,内容为npx --no-install commitlint --edit $1
:
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit $1'
在yorkie中使用
package.json
:
"gitHooks": {
"commit-msg": "commitlint --edit"
}
Test
经过安装commitlint
、commitlint.config.js
配置项,并且在hooks钩子中配置之后,就可以在提交时校验message
是否符合规范了。
输入不符合规范的message,将会出现如下的错误提示:
仅仅通过人工输入message,显然是不可靠的,commitlint
提供了一个可以生成message的工具@commitlint/prompt-cli
。
生成message方式一:commitlint
commitlint
为comitizen
提供了两种方式:
方式一:@commitlint/prompt-cli
Install
npm install --save-dev @commitlint/prompt-cli
Usage
在package.json
中加入一个npm run script
"scripts": {
"commit": "commit"
}
执行
git add .
npm run commit
运行npm run commit
将会出现如下图:
根据提示一步一步输入commit message
方式二:@commitlint/cz-commitlint
Install
npm install --save-dev @commitlint/cz-commitlint commitizen
Usage
package.json
{
"scripts": {
"commit": "git-cz"
},
"config": {
"commitizen": {
"path": "@commitlint/cz-commitlint"
}
}
}
执行
git add .
npm run commit
运行npm run commit
将会出现如下图:
根据提示一步一步输入commit message
prompt
可以在commitlint.config.js
配置文件中进行rules
和prompt
相关的规则,详细请查看官方文档戳这里。
检查历史提交message
npx commitlint -- --from HEAD~1 --to HEAD --verbose
生成message方式二:Commitizen
Commitizen是一个撰写合格 Commit message 的工具。
全局安装commitizen
npm install -g commitizen
项目初始化commitizen
在项目目录里,运行下面的命令,使其支持 Angular 的 Commit message 格式
// 使用npm包cz-conventional-changelog进行初始化
commitizen init cz-conventional-changelog --save --save-exact
执行完上述命令后,会往package.json
文件中的devDependencies
中加入cz-conventional-changelog
包,并且自动增加config
配置项,如下:
"devDependencies": {
"cz-conventional-changelog": "^3.3.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
之后,凡是用到git commit
命令,一律改为git cz
。这时就会出现选项,用来生成符合格式的commit message。
我们也可以在package.json
文件中的script
中配置命令:
"scripts": {
...
"commit": "git cz"
},
之后在执行git commit
时,直接运行npm run commit
即可!
完整版生成message示例
如果想生成Breaking changes
,请在Are there any breaking changes?
的时候选y
生成changelog
介绍
如果你的所有commit都符合Angular commit规范
,那么发布新版本时,就可以通过脚本自动生成changelog。
生成的changelog文档包括以下几个部分:
- Features(对应type: feat)
- Bug Fixes(对应type: fix)
- Code Refactoring (对应type: refactor且breaking changes为y)
- Performance Improvements(对应type: perf)
- Reverts (对应type: revert)
- BREAKING CHANGES (显示body中为BREAKING CHANGES的内容)
每个部分都会罗列相关的 commit ,并且有指向这些 commit 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容。
conventional-changelog-cli
用来生成changelog的工具 conventional-changelog-cli介绍
安装
npm install -g conventional-changelog-cli
生成changelog
使用下述命令可生成changelog:
conventional-changelog -p angular -i CHANGELOG.md -s
上面命令不会覆盖以前的 Change log,只会在CHANGELOG.md的头部加上自从上次发布以来的变动。
如果你想生成所有发布的 Change log,需要运行下面的命令:
conventional-changelog -p angular -i CHANGELOG.md -s -r 0
为了方便使用,可以将其写入package.json
的scripts
字段。
{
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
}
}
以后,直接运行下面的命令即可。
npm run changelog
changelog生成的依据
可能会有这样的疑问,如何生成某一个版本号所对应的changelog呢?
那就涉及到了package.json
中的version
字段,并且要在此版本开发完成的commit
上创建一个tag
。
这样,运行npm run changelog
的时候,就会根据version
和tag
生成对应的版本log。
示例
1. commit log如图:
2. 生成的changelog如图:
总结
代码检查
// 安装
npx mrm@2 lint-staged
// 在package.json中配置如下脚本检查
"lint-staged": {
"*.{js,vue}": [ // 对不同的后缀文件,运行不同的检查命令
"vue-cli-service lint",
"git add"
],
"*.{ts}": [ // 对不同的后缀文件,运行不同的检查命令
"xxx"
]
}
// husky中使用,`.husky/pre-commit`中,添加如下脚本:
npx lint-staged
// yorkie中使用,`package.json`中,添加如下脚本:
"gitHooks": {
"pre-commit": "lint-staged"
}
验证message规范性
脚本
package.json
"gitHooks": {
"commit-msg": "node build/verify-commit-msg.js"
}
build/verify-commit-msg.js
const chalk = require("chalk");
const msgPath = process.env.GIT_PARAMS;
const msg = require("fs")
.readFileSync(msgPath, "utf-8")
.trim();
const commitRE = /^(build|chore|ci|docs|feat|fix|wip|perf|refactor|revert|style|test|temp|)(\(.+\))?: .{1,50}/;
// 根据正则表达式校验提交的message是否符合团队规范
if (!(commitRE.test(msg) || msg.indexOf("Merge") === 0)) {
console.error(
` ${chalk.bgRed.white(" ERROR ")}
[${chalk.red(msg)}] 是 ${chalk.red("无效的提交消息格式")}
${chalk.red("自动生成更新日志需要正确的提交消息格式 例如:")}
${chalk.green("issue-1 feat(模块): 预发布环境增加 A 模块")}
${chalk.green("issue-2 fix(文案): 修复错误文案")}`
);
// 以非0值退出,放弃提交
process.exit(1);
}
commitlint
// 安装
npm install --save-dev @commitlint/cli @commitlint/config-conventional
// 配置
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
// 在husky中使用
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit $1'
// 在yorkie中使用
"gitHooks": {
"commit-msg": "commitlint --edit"
}
生成message
@commitlint/prompt-cli
// 安装
npm install --save-dev @commitlint/prompt-cli
package.json
配置script脚本:
"scripts": {
"commit": "commit"
}
// 提交时,直接运行npm run commit 即可
@commitlint/cz-commitlint
// 安装
npm install --save-dev @commitlint/cz-commitlint commitizen
package.json
:
{
"scripts": {
"commit":"git-cz"
},
"config": {
"commitizen": {
"path": "@commitlint/cz-commitlint"
}
}
}
// 提交时,直接运行npm run commit 即可
commitizen
npm install -g commitizen
// 切换至项目目录
commitizen init cz-conventional-changelog --save --save-exact
// 命令行执行git cz生成commit message
git cz // 或者package.json配置`scripts`
生成changelog
// 安装
npm install -g conventional-changelog
// 生成全部changelog
conventional-changelog -p angular -i CHANGELOG.md -s -r 0
// 生成自上次版本号变更以来changelog
conventional-changelog -p angular -i CHANGELOG.md -s
常见问题
1. gitHooks钩子验证时,仅可保留下述方式的其中一种:
.git/hoos/
目录下,去掉.sample
后缀后生效的钩子,如
package.json
中通过gitHoos
定义的钩子,可自定义通过npm包或者js文件去校验
2. 每一次版本发布记得修改package.json中的version版本,生成changelog需根据版本号去生成
参考代码库
- webpack:github.com/webpack/web…
- vue:github.com/vuejs/vue-n…