最终效果:每次提交代码时,自动完成以下两个功能
执行代码增量检查,有代码风格错误抛出异常。
检查提交的文件列表,如果同时存在 dist
目录和非 dist
目录,抛出异常。
前期准备
在阅读本文之前,请确保熟悉或了解 eslint
、 eslint-staged
和 husky
.
如果不了解,请点击传送门:Javascript代码检查那点事
代码增量检查
eslint 的具体配置不再赘述,在上述的传送门中有详细配置。
安装相关依赖
1 2
| npm install --save-dev husky npm install --save-dev lint-staged
|
在 package.json
中增加如下配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| "husky": { "hooks": { "pre-commit": "node scripts/utils/pre-commit.js" } }, "lint-staged": { "linters": { "*.js": [ "eslint", "git add" ], "*.vue": [ "eslint", "git add" ] }, "ignore": ["dist/**"] },
|
配置说明:当执行 git commit
时,会执行 husky.hooks.pre-commit
, 也就是 node scripts/utils/pre-commit.js
,该命令为执行一段脚本,脚本如下。
提交文件检查
检查提交内容的核心思路为:获取本次提交的改动文件列表信息 -> 检查文件路径 -> 判断是否同时存在 dist
和非 dist
目录,如果同时存在,则抛出异常停止 commit
操作,如果不存在,则执行 eslint
代码检查。详细代码如下(可直接拷贝到 scripts/utils/pre-commit.js
中)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| const chalk = require('chalk') const symbols = require('log-symbols') const spawn = require('child_process').spawn require('lint-staged')
getDiffFiles().then(files => { const filePaths = files.map(file => file.filename.split('/')[0]) let isDistFolder = false let isOtherFiles = false filePaths.forEach(path => { if (path === 'dist') isDistFolder = true else isOtherFiles = true }) if (isDistFolder && isOtherFiles) { throw new Error() } runCmd('lint-staged') }).catch(() => { console.error(`\n\n${symbols.error} ${chalk.redBright('Ops!Dist folder and other files cannot be submitted at the same time.')}`) console.log(` (use "git reset" to cancel the "add" operation)\n`) process.exit(1) })
function getDiffFiles() { return getHeadCommitId().then(head => { if (head) { const command = 'git -c core.quotepath=false diff-index --cached --name-status -M --diff-filter=ACM ' + head return runCmd(command).then(({ err, stdout, stderr }) => { return err || stderr ? err || new Error(stderr) : stdoutToResultsObject(stdout) }) } }) }
function getHeadCommitId() { return runCmd('git rev-parse --verify HEAD').then(({ err, stdout, stderr }) => { if (err && err.message.indexOf('fatal: Needed a single revision') !== -1) { return getFirstCommitId() } else { return err || stderr ? err || new Error('STDERR: ' + stderr) : stdout.replace('\n', '') } }) }
function getFirstCommitId() { return runCmd('git hash-object -t tree /dev/null').then(({ err, stdout, stderr }) => { return err || stderr ? err || new Error('STDERR: ' + stderr) : stdout.replace('\n', '') }) }
function runCmd(command) { return new Promise((resolve) => { const bits = command.split(' ') const args = bits.slice(1)
const cmd = spawn(bits[0], args, { cwd: process.cwd() })
let stdout = '' let stderr = ''
cmd.stdout.on('data', data => { stdout += data.toString() })
cmd.stderr.on('data', data => { stderr += data.toString() })
cmd.on('close', code => { const err = code !== 0 ? new Error(stderr) : null resolve({ err, stdout, stderr }) }) }) }
function stdoutToResultsObject(stdout) { const results = [] const lines = stdout.split('\n') let iLines = lines.length while (iLines--) { const line = lines[iLines] if (line !== '') { const parts = line.split('\t') const result = { filename: parts[2] || parts[1], status: codeToStatus(parts[0]), } results.push(result) } } return results }
function codeToStatus(code) { const map = { A: 'Added', C: 'Copied', D: 'Deleted', M: 'Modified', R: 'Renamed', T: 'Type-Change', U: 'Unmerged', X: 'Unknown', B: 'Broken', } return map[code.charAt(0)] }
|
当执行 git commit
操作时,首先会执行上述脚本,当满足要求时,再执行 eslint
代码检查,当代码检查通过后,才会提交代码到远程仓库!
全文完。