kuitos / kuitos.github.io

📝Kuitos's Blog https://github.com/kuitos/kuitos.github.io/issues
https://kuitos.github.io/
MIT License
1.13k stars 81 forks source link

基于git hooks的前端代码质量控制解决方案 #28

Open kuitos opened 8 years ago

kuitos commented 8 years ago

基于git hooks的前端代码质量控制解决方案

国际惯例先说下故事背景

通常情况下,如果我们是一个对代码质量有要求或者存在code review这一流程的团队,我们必然会有一套团队内部达成共识的code style从而提高项目的可维护性及代码的可读性。而确保提交到代码仓库的代码是符合规范的手段通常是,代码提交前由工具帮忙指出,如早期的jslint、jshint以及现在的eslint。提交后code review阶段由其他同学确保代码没有其他规范及质量问题。

目前这种方式的症结点

  1. 整个流程全靠团队成员自觉遵守。也就是说,即使我们在coding之前已经有一份code style放在那,而且eslint(jslint、jshint)工具已经配置好,依然有可能存在漏看了(或者根本没看。。)工具的提示信息、忘记了部分规范要求而直接把代码提交的情况。
  2. code review阶段reviewer经常要指出一些纯代码风格上的问题价值太低。因为上一条中出现的情况,reviewer还得花一些时间去指出纯代码风格上的问题,这种事情价值太低而且往往会让reviewer感到有心无力如果ta刚好还是个强迫症患者的话😂。
  3. 总之纯靠人肉去确保代码规范是一件价值很低而且很靠不住的事情。

    解决思路

既然人肉靠不住那我们只能让整个流程自动化让工具替我们完成代码规范检查的事情。我能想到的大概有这几种方式。

  1. 配置代码质量工具每次代码提交之前跑一下,然后针对工具给出的信息调整。
  2. 配置代码质量工具reviewer每次review之前跑一下,检查有没有基本的规范问题。
  3. 依靠CI(持续集成工具)对每次提交的代码做code check,每次接收push之前跑一下code check,如果没有通过直接拒绝接收push。

1、2两种方式都是通过工具方式降低了人肉检查代码规范的工作量,不过本质还是人肉。。
3方式不再人肉了但是依赖外部系统去做会存在风险及成本,比如哪天CI工具由bamboo切到了jenkins 然后又切到travis。。

直到有一天在下在fork了github上的一个项目并对其做了一定改造然后自信满满地准备提交代码的时候(json-mock-server),git一直在报错代码始终push不上去,报错信息也看不出什么东西,不行只能请教了对git比较内行的同事@arzyu,猜测是git hooks上配置了什么钩子脚本(后来证实是单元测试没覆盖到位),尝试把项目路径下的.git文件夹删除之后,终于能正常提交了😄

这件事给了我一个新的思路,就是我们能不能基于git的hook功能来做这这种自动化的事情呢?刚好在下又会一点点shell😄

所以理想的方式是

我们在git hooks里配置各种预处理脚本,比如代码检查或者跑单元测试之类的事情,如果我们的代码没有通过代码检查或者测试用例覆盖率不够,我们的push甚至commit会直接被拒绝。

好东西啊这不就是我这种极端分子想要的么哈哈!

怎么做

首先介绍一下git hooks是什么吧

钩子(hooks)是一些在"$GIT-DIR/hooks"目录的脚本, 在被特定的事件(certain points)触发后被调用。当"git init"命令被调用后, 一些非常有用的示例钩子文件(hooks)被拷到新仓库的hooks目录中; 但是在默认情况下这些钩子(hooks)是不生效的。 把这些钩子文件(hooks)的".sample"文件名后缀去掉就可以使它们生效了。

也就是在我们的git仓库下会有一个.git配置文件夹,它里面包含git操作相关的一系列 预处理/后处理 脚本。如 pre-commit、post-push之类的。

在一番google研究之后发现这事情操作起来并没有想象中那么简单,比如我们在什么时机将自己的脚本插入到hooks里,让使用者手动调命令这种主动式的方式一直不是我推崇的(要把调用者想象成懒癌晚期),然后处理脚本怎么写写哪里也没想到合适方式,一度放弃。

后来突然想起,之前那个开源项目是怎么做的?它是怎么把预处理脚本偷偷摸摸插入到hooks里的??于是突发奇想去研究别人的项目。

结果发现作者自己写了一个插件husky,专门用来处理这种git提交时的自动化处理。

大致用法像这样:

// 根目录package.json
"scripts": {
    "codecheck": "NODE_ENV=test eslint src/**/*.js",
    "test": "BABEL_JEST_STAGE=0 jest --verbose --watch",
    "precommit": "npm run codecheck && npm test"
}

配置了precommit之后每次代码提交之前git都会自动去跑代码检查及单元测试任务,都跑通过之后才能提交成功。更多用法请看项目主页husky

插件实现的机制大致是,在你install该插件时,它会自动往git hooks里埋入很多相应的钩子脚本(git hook能识别的),这些钩子函数会去读取package.json中的配置信息,当用户做某些git操作触发相应钩子时会自然去调用配置好的任务,从而实现我们的自动化需求,包括代码检查跟单元测试验证以及更多的自动化任务。

拓展思考

基于npm对install动作的钩子接口,我们可以提供一个插件,当使用者install该插件时插件会帮助用户做一系列初始化构建工作。开发时各业务模块独立仓库开发,上线或测试时提供构建插件一行install命令把所有业务模块组合起来变成一个完整的项目。具体打包、发布的方式后面会写一篇关于前端工程化的blog来介绍。

另外,基于git hooks我们还能做这样一件事情,我们在生产环境的git仓库中配置一个hook,当一有push/merge操作之后,触发一个推送脚本告知ci(jenkins/travis)执行构建/打包操作,然后我们只需要告知运维去某个地址拉下最新的包发布就好了(这里千万不要使用ci自己去完成发布),实现整个流程的自动化

ynCode commented 8 years ago

极端分子。。。。

arzyu commented 8 years ago

现在我这 js 代码检查从 jscs 切到了 eslint,清理完老代码后可以考虑用 git hooks 去做检查。

abell123456 commented 8 years ago

eslint 最近比较流行~

kuitos commented 8 years ago

@arzyu 我刚准备给你安利这个东西来着😄 尽快去玩玩,绝对好东西

kuitos commented 8 years ago

@abell123456 嗯,借es6发布之风😄

kuitos commented 8 years ago

@arzyu 其实你现在就可以用起来了,eslint里面可以配一个exclude列表,把以前的老代码加进去,老代码就不会走eslint检查了

Colindeng commented 8 years ago

质量度量在开发过程中度量比在提交代码时度量要更重要,比如静态检查、圈复杂度,函数出度和入度等、代码行数等指标、测试用例覆盖率等,编译代码即可看到这些指标是最好的,帮助立即发现问题并改进。设置一些阀值在提交代码时检查,超阀即进行限制是一种很好的控制手段,但前者,帮助改进意义更大。

kuitos commented 8 years ago

@Colindeng 你说的是这个么 https://github.com/flintjs/flint

Colindeng commented 8 years ago

可以看看SourceMonitor,在质量度量方面是比较强大,可惜SourceMonitor不支持Js。flint应该是偏向静态检查,质量度量应该比较弱吧。

xiaoDC commented 8 years ago

@arzyu @kuitos git diff 查找修改嘛,该过的文件就走eslint,新增的文件走eslint,老代码不改的话,就说明代码质量不错,就不用去eslint的,渐进式提升代码质量!

xdream86 commented 8 years ago

然后我们只需要告知运维去某个地址拉下最新的包发布就好了(这里千万不要使用ci自己去完成发布) @kuitos 有什么具体的原因吗?

kuitos commented 8 years ago

@xdream86 自动构建有可能出错如果直接发可能导致线上事故,存在风险。所以最后一步最好还是人工确认一下。

elainewu03 commented 8 years ago

代码风格方面可以通过写一些脚本配合工具进行自动检测,但是涉及到代码设计层面方面的,可能需要人工介入做代码审查工作。这个环节是不是也得加入到自动构建之前来做呢?

kuitos commented 8 years ago

@summerkai 是的

xbf321 commented 8 years ago

照着上面配置,出现以下错误提示,不怎么怎么回事? npm ERR! Darwin 14.5.0 npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "run" "codecheck" npm ERR! node v4.4.2 npm ERR! npm v3.9.5 npm ERR! code ELIFECYCLE npm ERR! @ codecheck: eslint src/**/*.js npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the @ codecheck script 'eslint src/*/.js'. npm ERR! Make sure you have the latest version of node.js and npm installed. npm ERR! If you do, this is most likely a problem with the package, npm ERR! not with npm itself. npm ERR! Tell the author that this fails on your system: npm ERR! eslint src/*/.js npm ERR! You can get information on how to open an issue for this project with: npm ERR! npm bugs npm ERR! Or if that isn't available, you can get their info via: npm ERR! npm owner ls npm ERR! There is likely additional logging output above.

luozt commented 6 years ago

现在可以安装 husky , lint-staged, prettier 插件,在git commit时对代码进行格式化或者其他操作,lint-staged可以只针对提交的文件进行处理,实在是太好用和方便了!

AimLuo commented 4 years ago

我看vue-cli中这样使用

  "gitHooks": {
    "pre-commit": "lint-staged",
    "commit-msg": "node scripts/verifyCommitMsg.js"
  },

而在大部分项目,如ant-design-pro-layout使用husky

  "husky": {
    "hooks": {
      "pre-commit": "npm run lint-staged"
    }
  },