利用git的pre-commit钩子函数对提交的代码进行校验

197 阅读2分钟

代码的校验一般都是用eslint来校验,但是有些代码的错误并不是语法上的错误,如A模块里不能引用B模块的代码,如果想要用eslint来校验,可能无能为力(当然你也可以自己专门写个规则),这时候我们就可以利用git的pre-commit钩子函数对提交的代码进行校验。

关于git钩子函数的描述请到:  传送门

找到目录下的.git目录下hooks文件夹(如果是子模块,请到modules找到对应模块的hooks目录),打开pre-commit文件(如果没有,则用pre-commit.sample文件复制一个,然后删除后缀.sample,就是一个没有后缀的文件)

在pre-commit文件中加入执行脚本的代码:

#!/bin/shcode=0
# 要执行的文件,注意路径,是在当前git模块的根目录
file='src/pre-commit.js'
if [ ! -f $file ]; then
    echo 'warn: Cannot find pre-commit.js. git pre-commit Check off'
    exit 0
fi
# 调用node执行文件
node $file
code=$(expr ${code} + $?)
if [ ${code} -eq 0 ]; then
    exit 0
else
    exit 1
fi

执行js文件的主要原理是用node执行git的命令,然后获得返回的结果;这里我们用child_process的exec方法,创建一个shell,然后在shell里执行命令。执行完成后,将stdout、stderr作为参数传入回调方法。

child_process.exec(command[, options][, callback])

我们用exec方法执行git查找不同的命令:git diff --cached --name-only --diff-filter=ACM -- "*.js" "*.vue";该命令只返回文件地址,然后我们只需要把文件地址拿到就可以用fs去读取文件内容了,然后校验文件每一行的内容。

// 查找提交代码中的不同,只返回不同文件的文件名,只比较新增复制和修改的文件,文件类型有js和vue文件
exec('git diff --cached --name-only --diff-filter=ACM -- "*.js" "*.vue"', (error, stdout) => {
  // stdout是文件地址字符串,只需要把文件地址拿到就可以用fs去读取文件内容了,然后校验文件内容
  if (stdout.length) {
    const pathList = stdout.replace(/^\s*|\s*$/g, '').split(/\s/)
    let errorCount = 0
    for (let filePath of pathList) {
      const texts = fs.readFileSync(filePath).toString().split('\n')
      // 校验不能引用moduleA模块的代码,如:@/moduleA
      const errors = texts.filter(x => {
        if (/@\/moduleA/.test(x)) {
          console.log('不能引用moduleA模块的代码')
          return true
        }
      })
      errorCount += errors.length
    }
    if (errorCount > 0) code = 1
    process.exit(code)
  }
  if (error !== null) {
    console.log(`exec error: ${error}`)  
  }
})