利用工具提升前端代码质量-版本自动化

最近在开发公司的UI组件库,目的是自造轮子,统一公司产品UI,及提升开发效率,不必从零做起。愿景虽美,仍有现实问题,其中就有这样一个点。

库总是需要更新,每次新版本如何发布,目前的操作是每次修改了代码后,提交,同时手动修改版本号,然后执行发布命令,但这样做问题很多,如下。

存在问题

  1. 每次修改点可能是个fix,也可能是个feat,又或者修改伴随着breaking change,单从commit信息上,提取不出任何的关键信息,同时,对外没有任何文档输出,假如项目中需要升级包,面对的只是一个个版本号,这样升级起来未免有些提心吊胆。
  2. 当前版本号的更新全依赖于人工输入,那么对于版本号的升级就必然出现不规范,不一致的情况,比如一个小的样式BUG的修改,一个新手可能就会直接升级大版本号。这样长此以往就必出问题,更别说手动的输入版本号本身也是个重复的体力劳动。
  3. 不只是所谓的UI组件库,即使是本身的业务项目,commit message应该是个很好的方式,去描述此次提交的内容,但当前Team中这一环很弱,并且内容简单随意,毫无实际意义。
  4. 因为commit的不规范,每次我们提交代码都会出发构建发版,但是实际上,假如只是doc修改,并不一定需要去触发构建发版,而假如想做到能够区分每次commit,那么就需要有规范格式化的commit存在。

以上四点问题支撑我思考,如何利用工具去改善。查阅了相关资料后,发现可以利用成熟化工具解决。

Angular项目参考-优秀样例

Angular项目的commit及changelog做的还是很专业的,羡慕吧,怎么做的呢,看下文。
https://github.com/angular/angular/commits/master

语义化版本

在配置之前,我们了解下语义化版本的规范,从而更好理解版本号变化的规则

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

  • 主版本号:当你做了不兼容的 API 修改,
  • 次版本号:当你做了向下兼容的功能性新增,
  • 修订号:当你做了向下兼容的问题修正。
    先行版本号及版本编译元数据可以加到“主版本号.次版本号.修订号”的后面,作为延伸。

以上摘自官网,戳这里

配置开搞

工具包安装

1
2
3
4
5
6
$ yarn add -D commitizen # 提交信息辅助工具
$ yarn add -D commitlint # commit lint utils
$ yarn add -D cz-conventional-changelog # Angular风格changelog
$ yarn add -D standard-version # 语义版本号及changelog生成控制
$ yarn add -D @commitlint/config-conventional # 提交信息lint

IDE插件安装

Git Commit Template

  • 我所在项目使用Jetbrains旗下的Intellij IDEA,因此这里贴出该平台的插件地址,其它IDE建议自行查找
  • GUI形式输入提交信息,相较终端会更友好高效

package.json

增加以下配置

1
2
3
4
5
6
7
8
9
10
11
"scripts": {
...
"commitmsg": "commitlint -e $GIT_PARAMS",
"release": "standard-version"
...
}
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}

commitlint.config.js

增加该文件

1
2
3
4
5
6
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"subject-case": [2, "never", ["upper-case"]]
}
};

.huskyrc.json

1
2
3
4
5
6
{
"hooks": {
"commit-msg": "commitlint -e $GIT_PARAMS",
}
}

.versionrc.json

配置戳这里

type说明

type用于表示此次改动的类型,目前常用的主要有以下几种:

  • feat 新功能(feature)表示在代码库中新增了一个功能(这和语义化版本中的 MINOR 相对应)
  • fix 表示在代码库中修复了一个 bug(这和语义化版本中的 PATCH 相对应)
  • to 只产生diff不自动修复此问题。适合于多次提交,最终修复问题提交时使用fix
  • docs 文档
  • style (格式化, 缺失分号等; 不包括生产代码变动)
  • refactor 重构
  • perf 性能优化
  • test 添加,重构测试; 不包括生产代码变动
  • chore (更新grunt任务等; 不包括生产代码变动)
  • revert (代码回滚)
  • build 构建打包
  • ci 持续集成,比如钩子机制修改,docker配置修改

详细配置项戳官方

完整项目配置,戳这里

  • to 是参考阿里的实践,具体可戳这里
  • 为什么需要to,因为存在这样一个场景,你的多次提交在服务一个fix,feat,那么需要这样一个type来去联系这几次的commit,同时changelog就可以去重这些提交历史,只显示一条,因为to类型会设置为false,不在changlog中体现。

操作步骤

提交执行

  1. 利用IDE执行提交,提交窗口下选择create commit template。按照表单描述,依次输入提交信息即可

  2. npm run release

    假如我们的前端项目需要发版,执行release命令,程序会自动更新CHANGELOG及包版本号,同时提交这两个文件。

    • 首次创建changelog及版本,执行命令npm run release -- --first-release
    • 执行版本发版命令建议使用CI服务器执行

注意细节

  1. 不符合我们约定格式的提交信息会在commit阶段报错,工具之所以可以做到原理是利用了git提供的各个操作阶段的hook实现。

  1. 因为利用的是hook实现的自动检测,当前检测是在本地,因此如果关掉本地的钩子即.huskyrc.json可以绕过检测,但不建议开挂。同时为了强制执行,也可以考虑引入git的server hook。

预发布版本

有时需要发布一个全新的版本,但是并不稳定,需要测试,同时也不想在原来的版本号上继续发展,这时我们可以执行预发布版本命令。

1
2
# alpha是版本号前缀,也可以是beta,rc
$ npm run release -- --prerelease alpha

alpha,beta, rc

如果是深度软件使用爱好者,或者一般的开发者应该都有所了解。因为比如尝鲜一些APP,肯定是知道beta,rc这些的。这里系统说明下

alpha版:内部测试版。α是希腊字母的第一个,表示最早的版本,一般用户不要下载这个版本,这个版本包含很多BUG,功能也不全,主要是给开发人员和 测试人员测试和找BUG用的。

beta版:公开测试版。β是希腊字母的第二个,顾名思义,这个版本比alpha版发布得晚一些,主要是给“部落”用户和忠实用户测试用的,该版本任然存 在很多BUG,但是相对alpha版要稳定一些。这个阶段版本的软件还会不断增加新功能。如果你是发烧友,可以下载这个版本。

rc版:全写:Release Candidate(候选版本),该版本又较beta版更进一步了,该版本功能不再增加,和最终发布版功能一样。这个版本有点像最终发行版之前的一个类似 预览版,这个的发布就标明离最终发行版不远了。作为普通用户,如果你很急着用这个软件的话,也可以下载这个版本。

stable版:稳定版。在开源软件中,都有stable版,这个就是开源软件的最终发行版,用户可以放心大胆的用了。

范例:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0。

个人认为,假如项目不大不需要搞这么复杂,灵活使用即可。

可能遇到的问题

  1. CHANGELOG中有重复项
  • 最近遇到了changelog不同版本列出了重复的提交,查了下官方仓库,原来是最近一个月的一次提交BUG导致,解决办法即重新安装包即可。如遇到同样问题建议卸载重装或升级,因为只是版本工具,时刻保持最新更好些。

    [官方Issue](https://github.com/conventional-changelog/conventional-changelog/issues/567)
    
    • standard-version包在创建新版本号,依据2个内容,1是package.json中的version即当前版本号,2是获取当前最新的taggit describe --tags --abbrev=0之后的所有提交。

      ​ 举个例子,如下图,如果手动删除本地的tag,v0.1.14,v0.1.13,执行npm run release,则新版本会包含两个版本中的所有提交,changelog因为配置了显示类别,因此这里会显示feat,build共两次提交

  1. 提交信息的检测原理就是shell配合git hooks,那么假如开发者有意无意的就是将hook关了,那么commit阶段还是可以过的,如果面临这样的问题,那么只能加上server hook来最终确保了。

写在最后

  • Commit message的规范性很重要,对比Angular的实践,你会看到显著的差距
  • 好的提交历史可以方便他人参与进来,也方便快速定位问题提交代码
  • 要知道的是利用这套工具去约束,强制使用,必然也是代价,但益大于弊
  • 好的习惯,受益终身,我们需要做的是尝试和接受这些好的习惯

参考文档