husky管理git hooks

190 阅读3分钟

git hooks

git 提供了在特定的动作发生时触发的自定义脚本,这些脚本分为两大类:客户端和服务器端的。

服务器端勾子包含 push 相关的操作;客户端勾子包含 commit 相关的操作。客户端的 hooks 存储在仓库的.git/hooks 文件夹里。

image-20220221101230345

如上图所示,这些 hooks 默认都会以 .sample 结尾,去掉 .sample 勾子才能生效。

执行时机

一般来说,以 pre 开头的勾子都是在该操作之前执行,以 post 开头的勾子都是在该操作之后执行。例如 pre-commit 会在提交动作之前执行,post-commit 会在提交动作之后执行。

所有的 git hooks

husky

husky 是一个 git hooks 管理工具,支持所有 git hooks

安装使用 husky

  1. 安装 husky
npm install husky --save-dev

这时 package.json 文件中已经存在 husky

//package.json
"devDependencies": {
  ...
  "husky": "^7.0.4"
},
  1. 使得 git hooks 生效
npx husky install

或者推荐使用以下命令,安装后自动让 git hooks 生效:

npm set-script prepare "husky install"

这时 package.json 文件中会多出一个 prepare 脚本

// package.json
{
  "scripts": {
    "prepare": "husky install"
  }
}

创建 hooks

使用npx husky add <file> [cmd]创建hooks,例如:

npx husky add .husky/pre-commit "npm test"

也可以不写后面的 cmd 命令,自己写一个 node.js 脚本:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"# 上面的代码是自动生成的,我们添加执行 node 脚本的命令如下
node imglint.js

这里我们编写一个脚本,每次提交时检测提交的文件中是否存在大于10kb 的图片,如果存在,则自动上川到远端服务器,并中断提交;否则,正常提交代码。编写 imglint.js如下:

const fs = require('fs');
const childProcess = require('child_process');
const util = require('util');
const exec = util.promisify(childProcess.exec);
​
/*
* 该脚本只针对 git 新增的文件进行处理,重命名以及内容更改的文件,不作处理*/
​
childProcess.execSync('git config core.quotepath false');
const commitFile = childProcess.execSync('git diff --cached --name-status').toString('utf-8').trim();
const commitFileArray = commitFile.split('\n');
​
const structResultArray = [];
const commandsArray = [];
commitFileArray.forEach(item => {
    if (item.startsWith('A\t')) {
        const filePath = item.substring(2);
        const zhReg = new RegExp(/[\u4e00-\u9fa5]/g);
        if (zhReg.test(filePath)) {
            console.log('\x1B[31mError Info: 您提交的文件命名存在中文,请修改文件名称!\x1B[0m');
            process.exit(1);
        }
        const picReg = new RegExp(filePath.startsWith('src/Images/') ? /.(png|jpe?g|gif|svg|json)$/g : /.(png|jpe?g|gif|svg)$/g);
        const fileSize = (fs.statSync(__dirname + '/' + filePath).size / 1024).toFixed(0);
        if (picReg.test(filePath) && fileSize >= 10) {
            const fileName = filePath.substring(filePath.lastIndexOf('/') + 1, filePath.length);
            commandsArray.push({
                command: `curl -H 'X-Auth-Token: <token>' -T '${filePath}' 'http://example.com/release/urlname/deploy?hostname=example.com&pathname=/zt/app/train/${fileName}'`,
                sourceFilePath: filePath, size: fileSize, fileName: fileName,
            });
        }
    }
});
​
if (commandsArray.length > 0) {
    console.log('\x1B[31mError Info: 以下图片的大小超过 10kB,些图片上传到静态资源网站,请删除图片并使用对应的 upload url 替换该图片的本地引用,重新提交代码\x1B[0m');
​
    Promise.allSettled(commandsArray.map(item => exec(item.command))).then(results => {
        results.forEach((result, index) => {
            if (result.status === 'fulfilled') {
                structResultArray.push({
                    'source file': commandsArray[index].sourceFilePath,
                    'upload url': `https://example.com/zt/app/train/${commandsArray[index].fileName}`,
                    'size(kb)': commandsArray[index].size,
                    status: 'success',
                });
            }
            if (result.status === 'rejected') {
                structResultArray.push({
                    'source file': commandsArray[index].sourceFilePath,
                    'upload url': '---------------------------',
                    'size(kb)': commandsArray[index].size,
                    status: 'failed',
                });
            }
        });
        console.table(structResultArray);
        process.exit(1);
    });
} else {
    process.exit(0);
}

在写上面脚本的过程中,使用了 crul这个命令行工具,对这个工具进行了一定的学习了解,个人感觉就是命令行版的 postman,很强大。

本人是第一次写node 脚本,不足之处,欢迎指出。

最后附上 commit 图片时的效果图:

image-20220221110223697

附录:

husky官网

all git hooks

git hooks