微信号:FrontDev

介绍:分享 Web 前端相关的技术文章、工具资源、精选课程、热点资讯

如何用 pre-commit 来检测代码

2016-12-02 20:47 伯乐专栏/小强

(点击上方公众号,可快速关注)


作者:伯乐在线专栏作者 - 前端-小强

点击 → 了解如何加入专栏作者

如需转载,发送「转载」二字查看说明


我们都知道接手一个项目是有多么的痛苦,没有文档,代码分格等等问题都不说了。今天说的 pre-commit 就是来帮助大家来检测代码的。

为什么要检测代码

code review是一个很费事,费时的事情,尤其在项目紧张期根本没有时间去做,而且说别人代码咋样咋样,但是被别人说自己的代码的时候,都不是太好!除非让老大来做code review。但是老大一般都没时间的!所以写个脚本来检测代码,符合规范,开(zhuang)心(bi)敲代码。

pre-commit

顾名思义’pre-commit‘,就是在代码提交之前做些东西,比如代码打包,代码检测,称之为钩子(hook)。可以理解为回调好了,在commit之前执行一个函数(callback)。这个函数成功执行完之后,再继续commit,但是失败之后就阻止commit了。

在.git->hooks->下面有个pre-commit.sample*,这个里面就是默认的函数(脚本)样本。

#!/bin/sh

#

# An example hook script to verify what is about to be committed.

# Called by "git commit" with no arguments.  The hook should

# exit with non-zero status after issuing an appropriate message if

# it wants to stop the commit.

#

# To enable this hook, rename this file to "pre-commit".

 

if git rev-parse --verify HEAD >/dev/null 2>&1

then

against=HEAD

else

# Initial commit: diff against an empty tree object

against=4b825dc642cb6eb9a060e54bf8d69288fbee4904

fi

 

# If you want to allow non-ASCII filenames set this variable to true.

allownonascii=$(git config --bool hooks.allownonascii)

 

# Redirect output to stderr.

exec 1>&2

 

# Cross platform projects tend to avoid non-ASCII filenames; prevent

# them from being added to the repository. We exploit the fact that the

# printable range starts at the space character and ends with tilde.

if [ "$allownonascii" != "true" ] &&

# Note that the use of brackets around a tr range is ok here, (it's

# even required, for portability to Solaris 10's /usr/bin/tr), since

# the square bracket bytes happen to fall in the designated range.

test $(git diff --cached --name-only --diff-filter=A -z $against |

  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0

then

cat <<\EOF

Error: Attempt to add a non-ASCII file name.

 

This can cause problems if you want to work with people on other platforms.

 

To be portable it is advisable to rename the file.

 

If you know what you are doing you can disable this check using:

 

  git config hooks.allownonascii true

EOF

exit 1

fi

 

# If there are whitespace errors, print the offending file names and fail.

exec git diff-index --check --cached $against --


这里面应该是一段shell脚本,博主不懂shell脚本。这可怎么办呢?

npm script

之前看到一篇《Run npm scripts in a git pre-commit Hook》, 可以利用npm script来做脚本。

安装pre-commit

npm install pre-commit --save-dev


修改package.json

"scripts": {

    "test": "npm -v && node -v",

    "start": "node index.js",

    "eslint": "node check.js" // 检查的脚本

  },

  "pre-commit": [

    "eslint" // 与scripts中的脚本名称一一对应

  ],


问题

按照之前的那篇文章,接下来更改某个文件,应该是可以执行check脚本了,但是博主window并没有pre-commit。

在github上找到了原因, 因为在window下pre-commit npm,由于权限问题,导致无法在hooks文件下生成文件。

需要以管理员打开cmd,执行node ./node_modules/pre-commit/install.js就可以了。o(╯□╰)o

检测脚本check

隐患检测

博主一开始的思路就是使用eslint检测潜在的错误,由于eslint比较严格,一下子会有很多的error,可以在项目里面新建.eslintrc文件, 用来覆盖默认的严格的eslint rules。

但是博主又有个问题了!就是检测代码的时候,由于引用是第3方的库,比如框架、组件、ui库等等。这些应该不需要检测的,不要影响项目本身的代码。这里就需要在项目里新建个.eslintignore文件,用来忽略检测的文件夹。

这个时候执行eslint ./ --cache,会有很多warnings,巴拉巴拉一大推,o(╯□╰)o。参考ESLint配置,执行eslint ./ --cache --quiet,就可以只报出error的信息了。到项目后期,可以慢慢将eslint越来越严格,甚至warn也不允许。

var exec = require('child_process').exec;

var fs = require('fs');

var errTip = ['还存在很多错误的地方哦!,避免隐患,还是现在改了吧!', '哎呀呀!还有错误哦!'];

var successTip = ['不错哦!加油!', '赞!', '棒棒哒!'];

var lint = function(cb) {

    exec('eslint ./ --cache --quiet', function(error, stdout, stderr) {// 通过node子进程执行命令

        if(stdout) {

            console.log('\x1B[31m%s',errTip[Math.floor(errTip.length*Math.random())]);

            console.log('\x1B[37m', stdout);//输出eslint错误信息

            cb(1);

            return;

        }

        cb(0);

    });

}

 

var taskList = [lint];

// 执行检查

var task = function() {

    if(!taskList.length) {

        console.log('\x1B[32m%s', successTip[Math.floor(successTip.length*Math.random())]);

        process.exit(0);

        return;

    }

    var func = taskList.shift();

    func(function(pass) {

        if(pass === 1) {

            process.exit(1);

            return;

        }

        task();

    });

}

 

var startTask = function() {

    console.log('开始检查代码咯!O(∩_∩)O~\n');

    task();

}

 

// 执行检查

startTask();


规范检测

除了一些隐患要检测,还可能要检测一些代码规范,tab键和空格键乱用等等,这个适合各个团队不同的情况。

但是现在一下子接手个项目,一下子全部去改造有点不现实。试想能不能只对修改的文件进行检查?其实是可以的。

通过git diff HEAD --name-only --diff-filter=ACMR命令能够拿到修改过的代码的文件列表,同时我们新增了一个第三方的库,也可以再添加参数,过滤不需要的文件夹。

核心代码

//name为检测的文件夹,如‘modules component static’

exec('git diff HEAD --name-only --diff-filter=ACMR -- '+name+'', function(error, stdout, stderr) {// 通过node子进程执行命令,

    if(stdout) {

        array = stdout.split('\n');//通过切割换行,拿到文件列表

        array.pop();// 去掉最后一个换行符号

        array.forEach(function(value) {

            text = fs.readFileSync(value, 'utf-8');// 拿到文件内容

            if(检测函数) {

                cb(1);

                return;

            }

        });

        cb(0);

    }else {

        cb(0);

    }

});


实例检测函数

博主有些点点洁癖,由于每个人的代码编辑器不一样!最简单的分格就是tab键和空格键混用。所以就写个很简单的检测tab键和空格的函数。

var extraTab = function(cb) {

    var conf = JSON.parse(fs.readFileSync('./.check', 'utf8'));

        var name = conf.dir.join(' ');

        var bTabAndSpace = conf.bTabAndSpace;

        var array;

        var text;

        var checkTab = function(text, name) {//检测函数

            if(/\t\s/.test(text)) {

                console.log('\x1B[31m%s', name);

                console.log('\x1B[37m', '存在tab键和空格键乱用哦!');

                return false;

            }

            return true;

        };

        exec('git diff HEAD --name-only --diff-filter=ACMR -- '+name+'', function(error, stdout, stderr) {// 通过node子进程执行命令

            if(stdout) {

                array = stdout.split('\n');//通过切割换行,拿到文件列表

                array.pop();// 去掉最后一个换行符号

                array.forEach(function(value) {

                    text = fs.readFileSync(value, 'utf-8');// 拿到文件内容

                    if(bTabAndSpace && !checkTab(text, value)) {//检测函数

                        cb(1);

                        return;

                    }

                });

                cb(0);

            }else {

                cb(0);

            }

        });

};


将extraTab加入taskList任务队列里面就可以了!

总结

如果项目实在没时间去改的话,可以git commit -m 'XXX' --no-verify强制提交。也欢迎大家在https://github.com/xiaoqiang730730/pre-commit-check 提交一些规范类的代码测试!↖(^ω^)↗


关注「前端大全」

看更多精选前端技术文章

↓↓↓



专栏作者简介 ( 点击 → 加入专栏作者 


前端-小强:前端-小强,前端工程师(微博 http://weibo.com/smallwall520),现就职于杭州光云科技。

打赏支持作者写出更多好文章,谢谢!

 
前端大全 更多文章 Chrome开发者工具详解(1):Elements、Console、Sources面板 漫画:脚本自动化的理想和现实 3种 web 会话管理的方式 一道 JS 面试题引发的思考 一道 JS 面试题引发的思考
猜您喜欢 mnv*框架时代 五大常用算法之五:分支限界法 Yelp的实时流技术:利用MySQLStreamer将数据库变更发送给Kafka 有钱没钱回家过年,传智提前给大家拜年啦! 开奖 | 现在是见证奇迹的时刻