function runCommand(cwd, hookName, cmd, env) {
console.log(`husky > ${hookName} (node ${process.version})`);
const { status } = child_process_1.spawnSync('sh', ['-c', cmd], {
cwd,
env: Object.assign(Object.assign({}, process.env), env),
stdio: 'inherit',
});
if (status !== 0) {
const noVerifyMessage = [
'commit-msg',
'pre-commit',
'pre-rebase',
'pre-push',
].includes(hookName)
? '(add --no-verify to bypass)'
: '(cannot be bypassed with --no-verify due to Git specs)';
console.log(`husky > ${hookName} hook failed ${noVerifyMessage}`);
}
// If shell exits with 127 it means that some command was not found.
// However, if husky has been deleted from node_modules, it'll be a 127 too.
// To be able to distinguish between both cases, 127 is changed to 1.
if (status === 127) {
return 1;
}
return status || 0;
}
目录
背景
基于react开发了一套通用模版,在模版内集成了,通用的eslint、prettier等规则,结合huksy+lintstaged来做代码质量与规范的检查,husky选用的是4.3.8版本,package.json如下图所示;
主要使用到husky的两个钩子
pre-commit
与commit-msg
但是在部分同事的电脑上,install之后,huksy没有初始化成功,也没有错误提示,导致无法正常使用husky的功能,为了彻底解决这个问题,决定去看一下husky的内部实现
husky4.3.8源码分析
husky是在install的时候,往.git/hooks目录下注入对应的commit钩子,那么先看package.json
关键上面这三个script hook
先看
postinstall
这个钩子就是做了一些辅助工具,无需关注重点是
install
这个钩子,install这个钩子做的事情如下检查git版本 => 从环境变量INIT_CWD中获取到当前工作目录 => 创建各种git hook => 创建husky.local.sh 与 husky.sh 用于具体执行huksy命令的脚本
初始化准备工作
在执行install or uninstall之前会做一些当前工作目录及git版本的检查,这里两个地方会中断执行,导致install失败
创建hook
当满足上述条件之后,就会执行对应的install or unstall方法
install成功之后,我们可以在.git/hooks内看到生成的hook,如下图所示
具体的hook内容如下所示
到这里我们基本已经知道为什么部分电脑husky不生效,原因主要就是git版本低于指定的2.13.0版本,还有就是无法从环境变量中获取到INIT_CWD
排查错误并手动执行install
这里把husky内的debug日志开启,便于排查问题 所以当我们提示的是git版本低于要求版本时,则可以通过升级git版本来解决该问题
husky执行命令实现
通过shell方式执行,然后通过status来判断成功还是失败,所以如果我们自己自定义了一些工具,那么如果需要借助huksy来执行,出现错误的场景,一定需要通过process.exit(code)把code向上传递出来
总结
husky的runCommand执行方式值得我们在写类似工具时借鉴一二,另外就是为什么我们在install的时候,husky如果初始化失败,为什么没有中断整个install流程?后续有时间在去了解下这里