Git Commit代码校验(基于husky二次封装)和提交注释校验

134 阅读2分钟

目标

  • 做入库前的代码质量校验,提升代码质量
  • 统一代码格式,提升代码可读性

使用husky + lint-staged + eslint + stylelint + pretiier 做代码校验

配置husky

  1. 配置prepare脚本命令

编辑package.jsonscript里添加prepare的值为husky install

json
复制代码
  "scripts": {
      "prepare":"husky install"
  },

利用npm 内置脚本命令prepare(注意:如果通过 git 安装的包包含prepare脚本,则在打包和安装包之前,将安装其依赖项和 devDependencies,并运行prepare脚本。)

执行 husky install 实际上就是创建 .husky 目录,复制../husky.sh文件到该目录下,配置了一个.gitignore,设置了core.hooksPath(设置 .husky 目录为 git hooks 目录)

  1. 配置pre-commit

.husky目录下创建pre-commit (git的钩子,会在git commit之前执行)

bash
复制代码
#!/bin/sh
# 执行当前当前目录下指定的文件,并执行该路径下的 _/husky.sh 文件
# $0 为 当前脚本名称 调用 husky.sh 脚本
. "$(dirname "$0")/_/husky.sh"

npm run lint:lint-staged

配置lint-staged

lint-staged 是一个在 git 暂存文件上(也就是被 git add 的文件)运行已配置的 linter(或其他)任务。lint-staged 总是将所有暂存文件的列表传递给任务。

Lint-staged是一个基于Node.js的库,它可以对Git仓库中的暂存区(staged)代码进行线性检测,从而确保代码质量

我们选择单独一个.lintstagedrc.js来写lint-staged的配置,放在.husky目录下

  1. 配置lint:lint-staged命令

由于pre-commit文件最后一行是执行lint:lint-staged,所以在package.json中添加lint:lint-staged命令。

json
复制代码
"scripts": {
    "prepare":"husky install""lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
 }
  1. 配置lintstagedrc.js文件

less
复制代码
module.exports = {
    'src/**/*.{js,jsx,ts,tsx,vue}': ['eslint --fix', 'prettier --write'],
    'src/**/*.{scss,less,styl,html,vue}': ['stylelint --fix', 'prettier --write'],
};

配置eslint + stylelint + prettier

  1. 前置安装包

arduino
复制代码
yarn add -D eslint prettier vue-eslint-parser eslint-plugin-vue eslint-define-config eslint-config-prettier eslint-plugin-prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser stylelint postcss postcss-less postcss-html stylelint-config-prettier stylelint-config-recommended-less stylelint-config-standard stylelint-config-standard-vue stylelint-less stylelint-order 

然后分别针对eslint、stylelint、prettier配置

可以参考往期文章

eslint 规则配置及说明

Stylelint规则配置及说明

Prettier 规则配置及说明

.eslintrc.js

php
复制代码
// @ts-check
const { defineConfig } = require('eslint-define-config');
module.exports = defineConfig({
  root: true,
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  parser: 'vue-eslint-parser',
  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaVersion: 2020,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
    },
  },
  plugins: ['vue', 'prettier', '@typescript-eslint'],
  //注意extends数组的顺序,数组后面的会覆盖前面规则
  extends: [
    'eslint:recommended',
    'plugin:prettier/recommended',
    'plugin:vue/vue3-recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier',
  ],
  rules: {
    'no-use-before-define': 'off',
    'no-case-declarations': 'off',
    'no-async-promise-executor': 'off',
    'no-empty': 'warn',
    'prefer-const': 'warn',
    'no-prototype-builtins': 'warn',
    'no-var': 'error',
    'vue/valid-v-for': 'warn',
    'vue/no-unused-vars': 'warn',
    'vue/require-v-for-key': 'warn',
    'vue/attributes-order': 'off',
    'vue/v-on-event-hyphenation': 'off',
    'vue/multi-word-component-names': 'off',
    'vue/one-component-per-file': 'off',
    'vue/html-closing-bracket-newline': 'off',
    'vue/max-attributes-per-line': 'off',
    'vue/multiline-html-element-content-newline': 'off',
    'vue/singleline-html-element-content-newline': 'off',
    'vue/attribute-hyphenation': 'off',
    'vue/require-default-prop': 'off',
    '@typescript-eslint/no-this-alias': 'off',
    '@typescript-eslint/ban-ts-ignore': 'off',
    '@typescript-eslint/no-unused-vars': 'warn',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
    '@typescript-eslint/no-var-requires': 'off',
    '@typescript-eslint/no-empty-function': 'off',
    '@typescript-eslint/no-use-before-define': 'off',
    '@typescript-eslint/ban-ts-comment': 'off',
    '@typescript-eslint/ban-types': 'off',
    '@typescript-eslint/no-non-null-assertion': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-inferrable-types': 'off',
  },
});

.stylelintrc.js

css
复制代码
module.exports = {
    extends: [
      'stylelint-config-standard',
      'stylelint-config-prettier',
      'stylelint-config-recommended-less',
      'stylelint-config-standard-vue'
    ],
    plugins: ['stylelint-order'],
    // 不同格式的文件指定自定义语法
    overrides: [
      {
        files: ['**/*.(less|css|vue|html)'],
        customSyntax: 'postcss-less'
      },
      {
        files: ['**/*.(html|vue)'],
        customSyntax: 'postcss-html'
      }
    ],
    ignoreFiles: [
      '**/*.js',
      '**/*.jsx',
      '**/*.tsx',
      '**/*.ts',
      '**/*.json',
      '**/*.md',
      '**/*.yaml'
    ],
    rules: {
      'no-descending-specificity': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
      'selector-pseudo-element-no-unknown': [
        true,
        {
          ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted']
        }
      ],
      'selector-pseudo-class-no-unknown': [
        true,
        {
          ignorePseudoClasses: ['deep']
        }
      ],
      // 指定样式的排序, 从定位到元素内容,从外到内,从底层到上层排列,最后是一个其他特性
      'order/properties-order': [
        'display',
        'position',
        'top',
        'right',
        'bottom',
        'left',
        'margin',
        'margin-top',
        'margin-right',
        'margin-bottom',
        'margin-left',
        'padding',
        'padding-top',
        'padding-right',
        'padding-bottom',
        'padding-left',
        'border',
        'border-style',
        'border-width',
        'border-color',
        'border-top-style',
        'border-top-width',
        'border-top-color',
        'border-right-style',
        'border-right-width',
        'border-right-color',
        'border-bottom-style',
        'border-bottom-width',
        'border-bottom-color',
        'border-left-style',
        'border-left-width',
        'border-left-color',
        'border-radius',
        'z-index',
        'justify-content',
        'align-items',
        'float',
        'clear',
        'overflow',
        'overflow-x',
        'overflow-y',
        'width',
        'min-width',
        'max-width',
        'height',
        'min-height',
        'max-height',
        'background',
        'background-position',
        'background-repeat',
        'background-size',
        'background-color',
        'background-clip',
        'font-size',
        'font-family',
        'text-align',
        'text-justify',
        'text-indent',
        'text-overflow',
        'text-decoration',
        'white-space',
        'color',
        'visibility',
        'opacity',
        'filter',
        'list-style',
        'outline',
        'box-shadow',
        'text-shadow',
        'resize',
        'transition'
      ]
    }
  }

.prettierrc.js

yaml
复制代码
module.exports = {
    printWidth: 100,
    semi: true,
    vueIndentScriptAndStyle: true,
    singleQuote: true,
    trailingComma: 'all',
    proseWrap: 'never',
    htmlWhitespaceSensitivity: 'strict',
    tabWidth: 2,
    endOfLine: 'auto',
};

用commitlint做提交注释校验

前置安装包

bash
复制代码
npm install -D @commitlint/cli @commitlint/config-conventional

Commitlint配置文件

.commitlintrc.js

css
复制代码
module.exports = {
    ignores: [(commit) => commit.includes('init')],
    extends: ['@commitlint/config-conventional'],
    rules: {
      'body-leading-blank': [2, 'always'],
      'footer-leading-blank': [1, 'always'],
      'header-max-length': [2, 'always', 108],
      'subject-empty': [2, 'never'],
      'type-empty': [2, 'never'],
      'subject-case': [0],
      'type-enum': [
        2,
        'always',
        [
          'feat',
          'fix',
          'style',
          'docs',
          'test',
          'refactor',
          'chore',
          'revert',
        ],
      ],
    },
  };
  

生成Change log文件

目前项目还没有自动生产change log日志的需求,后续有需求可以通过类似conventional-changelog的工具生成

配置独立为npm包

上面的配置项很多,每个项目都需要拷贝一份,很繁杂也容易出错。所以作为第三方包来引用

方案一:创建一个类似create-app的工具,在通过模板生成项目的时候拷贝。缺点是已经存在的项目还是只能拷贝,也无法升级

方案二:做一个类似husky的工具,安装时将工具内部的eslint/stylelint/prettier相关的配置文件拷贝到根目录下,依赖的相关包会自动安装,也避免了在项目中写一大堆依赖包

最终选择第二个方案.

仓库引用及地址 说明

##目 录 结 构

configs // .husky+commitlint+eslint + stylelint + prettier + commitlint等 配置集合
    -- .husky // git hooks .husky文件配置
    -- .commitlintrc.js // commitlint配置
    -- .eslintignore.ts // eslint忽略配置
    -- .eslintrc.js // eslint配置
    -- .prettierrc.js // prettier配置(美化代码)
    -- .stylelintrc.js // stylelint配置
    --  tsconfig.json // 
lib // 组件编译输出目录
    -- bin.js//  .bin可执行文件入口
    -- index.js // 仓库入口文件 
    -- index.d.ts // 
    -- bin.d.ts//

.bin可执行文件入口代码说明

向外暴露了 h-com-linters install 和h-com-linters uninstall两个Shel命令 假设你已经执行了npm install h-com -linters在你的工程项目安装了 h-com -linters 那么 执行npx h-com-linters install 会执行husky install 在你的工程项目根目录创建.husky文件夹,并把git hooks 配置关联到.husky文件夹,然后把nodemodles下 h-com-linters包 中configs文件夹下的配置全部复制的你的工程项目中,这样就一键配置好了.husky+eslint + commitlint + stylelint + prettier + commitlint 也可以用 npx h-com-linters uninstall 卸载husky

#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const p = require("path");
const h = require("./");
function help(code) {
    console.log(`Usage:
  h-com-linters install
  h-com-linters uninstall
  `);
    process.exit(code);
}
const [, , cmd, ...args] = process.argv;
const ln = args.length;
const [x] = args;
const cmds = {
    install: () => (ln > 1 ? help(2) : h.install(x)),
    uninstall: h.uninstall,
    ["-v"]: () => console.log(require(p.join(__dirname, "../package.json")).version),
};
try {
    cmds[cmd] ? cmds[cmd]() : help(0);
}
catch (e) {
    console.error(e instanceof Error ? `h-com-linters - ${e.message}` : e);
    process.exit(1);
}

github仓库地址:github.com/raincolor/H… npm 包地址:www.npmjs.com/package/h-c…

使用 1.安装 h-com-linters

复制代码
npm install h-com -linters

2.IDE 安装 eslint、stylelint、prettier 插件,用于编码时的提醒

3.在 package.json 中添加

json
复制代码
// windows
"scripts": {
    "prepare": "h-com-linters install",
}
// mac pre-commit等在mac下不被认可为可执行文件
"scripts": {
    "prepare": "h-com-linters install && chmod +x .husky/*",
}

执行(windows 推荐使用 git bash,'h-com-linters install && chmod +x .husky/*'命令就会不报错)

csharp
复制代码
yarn add -D h-com-linters

注意:更新h-com-linters 也使用上面这条命令,这样才能触发执行 scripts.prepare

h-com-linters 自动会安装相关的依赖包,并将 husky 配置、代码检查相关配置、commit 提交配置都拷贝到项目下。

4.还可以作为一个简易的脚手架使用

npm h-com-linters -g 全局安装后

npx h-com-linters clicreate yourProjectName 会在当前目录生成./yourProjectName文件夹 文件夹中有configs中的配置文件 和 包含对应依赖的package.json 文件