Eslint与Git搭配笔记(一)

585 阅读2分钟

核心目标:实现如果提git commit的文件中存在eslint报错,就终止commit(merge-commit除外)

Eslint接口用法

根据官网的示例,我们可以通过如下代码获取到指定文件的Eslint报错信息

const fs = require('fs');
const CLIEngine = require('eslint').CLIEngine;

const cli = new CLIEngine({
    parser: '@babel/eslint-parser',
    env: {
        browser: true
    },
    extends: '../rules/index'
});
const code = fs.readFileSync('../test/index.jsx', 'utf-8');
const report = cli.executeOnText(code);

console.log(report.results[0].messages);

对于test/index.jsx文件件,测试内容如下:

import React from 'react';
import PropTypes from 'prop-types';

new Buffer(5);
new Buffer([1, 2, 3]);

得到的输出结果是:

[
    {
        ruleId: 'no-unused-vars',
        severity: 2,
        message: "'React' is defined but never used.",
        line: 1,
        column: 8,
        nodeType: 'Identifier',
        messageId: 'unusedVar',
        endLine: 1,
        endColumn: 13
    },
    {
        ruleId: 'no-unused-vars',
        severity: 2,
        message: "'PropTypes' is defined but never used.",
        line: 2,
        column: 8,
        nodeType: 'Identifier',
        messageId: 'unusedVar',
        endLine: 2,
        endColumn: 17
    },
    {
        ruleId: 'import/no-extraneous-dependencies',
        severity: 2,
        message: "'prop-types' should be listed in the project's dependencies. Run 'npm i -S prop-types' to add it",
        line: 2,
        column: 23,
        nodeType: 'Literal',
        endLine: 2,
        endColumn: 35
    },
    {
        ruleId: 'no-new',
        severity: 2,
        message: "Do not use 'new' for side effects.",
        line: 4,
        column: 1,
        nodeType: 'ExpressionStatement',
        messageId: 'noNewStatement',
        endLine: 4,
        endColumn: 15
    },
    {
        ruleId: 'no-buffer-constructor',
        severity: 2,
        message: 'new Buffer() is deprecated. Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead.',
        line: 4,
        column: 1,
        nodeType: 'NewExpression',
        messageId: 'deprecated',
        endLine: 4,
        endColumn: 14
    },
    {
        ruleId: 'no-new',
        severity: 2,
        message: "Do not use 'new' for side effects.",
        line: 5,
        column: 1,
        nodeType: 'ExpressionStatement',
        messageId: 'noNewStatement',
        endLine: 5,
        endColumn: 23
    },
    {
        ruleId: 'no-buffer-constructor',
        severity: 2,
        message: 'new Buffer() is deprecated. Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead.',
        line: 5,
        column: 1,
        nodeType: 'NewExpression',
        messageId: 'deprecated',
        endLine: 5,
        endColumn: 22
    }
];

我们可以获知一个错误的级别、所处的位置、报错内容、错误名称等信息,这些信息足够我们定位问题。如果没有报错,则 report.results[0].messages 是一个空数组。

如何获取Git提交文件

修改.git/hooks/文件夹下的文件,可以执行对应的钩子函数

在钩子函数里执行如下命令 git diff --staged --diff-filter=ACMR --name-only -z,可以得到缓存区(被commit的都是进入缓存区的)里对应的变化文件。

其中--diff-filter取值的含义是:

  • Added (A),
  • Copied (C)
  • Deleted (D)
  • Modified (M)
  • Renamed (R)

与Git的结合

我们可以利用husky+lint-staged实现上述功能

常见问题

  • 如果安装husky之后发现.git/hooks/文件夹下面没有生成对应的钩子脚本,可以试着尝试更改nodenpm版本,我安装4.3.8版本的husky,如果node版本是9.11.2就不成功,改为13.10.2就成功了。查阅文档发现一行小字:Existing hooks are kept. Requires Node >= 10 and Git >= 2.13.0.。不过究竟是升级后哪个地方导致的,目前还不清楚。其实husky的这点很不友好,因为在团队开发中,存在无法统一 node 版本的情况,会出现钩子执行覆盖不到的情况。针对这种情况,我们可以自己编写一个npm script,利用pre&post特性,给项目必用的命令添加前置或后置命令,自己覆盖掉.git/hooks/里的指定命令。