Node 后端 git 提交规范化处理

Node 后端 git 提交规范化处理

创建项目

以 koa 为例

使用 koa-generator 创建项目

# 安装
npm install -g koa-generator
# 创建项目
koa2 test-demo
# 安装依赖
cd test-demo
npm install
# 启动
npm run dev

访问 http://localhost:3000/

创建 .gitignore 忽略掉 node_modules

node_modules/

windows 系统 注意把 dev 路径的 斜杠(/)替换成 (\\)

提交前检查

代码格式

使用 eslint + prettier

# 安装
npm install eslint eslint-config-airbnb-base eslint-plugin-import eslint-config-prettier eslint-plugin-prettier -D

创建 .eslintrc.js

module.exports = {
  env: {
    commonjs: true,
    es2020: true,
    node: true,
    jest: true,
    es6: true,
  },
  extends: ['airbnb-base', 'plugin:prettier/recommended'],
  parserOptions: {
    ecmaVersion: 12,
  },
  plugins: ['prettier'],
  rules: {
    'no-unused-vars': 0,
    'no-console': 'off',
    'max-classes-per-file': 0,
    'prettier/prettier': [
      'error',
      { singleQuote: true, semi: false, arrowParens: 'avoid' },
    ],
    'arrow-body-style': 'off',
    'prefer-arrow-callback': 'off',
  },
}

创建 .eslintignore

node_modules/

在跟目录创建一个 src 文件夹,将 public,routes,view 放到 src 下

同时也将 app.js 放到 src 下,并且修改 bin/www 将 const app = require('../app') 改为 const app = require('../src/app')

在 package.json 创建脚本

"script": {
	...,
    "lint": "eslint \"src/**/*.{js,ts}\"",
    "lint-fix": "eslint --fix \"src/**/*.{js,ts}\""
}
# lint 检查
npm run lint

参考

Airbnb JavaScript 代码规范

eslint

代码测试

这里使用 jest
# 安装
npm install --save-dev jest

在根目录创建 __test__ 文件夹

在目录下创建 sum.test.js

function sum(a, b) {
  return a + b
}
test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3)
})

更多写法参考

配置执行脚本,参数

"script": {
    "test": "jest --runInBand --passWithNoTests --colors --forceExit",
}
# 执行
npm run test

接口测试

这里使用 supertest

# 安装
npm install supertest --save-dev
# 安装 axios
npm install axios --save-dev

__test__ 下创建 apis 文件夹

创建 _server.js 文件,使用 supertest mock 请求接口

const axios = require('axios')
const supertest = require('supertest')

let request
const app = require('../../src/app')

const isTestLocal = process.env.NODE_ENV === 'local'
const isTestRemote = process.env.NODE_ENV === 'remote'

if (isTestLocal) {
  // 通过 supertest 创建服务
  const server = app.callback()
  request = supertest(server)
}

// 测试机 host
const REMOTE_HOST = 'http://localhost:3000'

/**
 * 发送请求
 * @param {*} method
 * @param {*} url
 * @param {*} bodyOrParams
 * @param {*} headers
 */
async function ajax(method = 'get', url = '', bodyOrParams = {}, headers = {}) {
  // 如果有 token 可以在 headers 设置

  let result

  // 本身测试,使用 supertest
  if (isTestLocal) {
    let res
    if (method === 'get') {
      res = await request[method](url).query(bodyOrParams).set(headers)
    } else {
      res = await request[method](url).send(bodyOrParams).set(headers)
    }
    result = res
  }

  // 远程测试机,使用 axios
  if (isTestRemote) {
    const remoteUrl = `${REMOTE_HOST}${url}`
    const conf = {
      method,
      url: remoteUrl,
      headers,
    }
    if (method === 'get') {
      conf.params = bodyOrParams
    } else {
      conf.body = bodyOrParams
    }
    const res = await axios(conf)
    result = res
  }

  // 返回结果
  return result
}

module.exports = {
  async get(url, params, headers) {
    const res = await ajax('get', url, params, headers)
    return res
  },
  async post(url, body, headers) {
    const res = await ajax('post', url, body, headers)
    return res
  },
  async patch(url, body, headers) {
    const res = await ajax('patch', url, body, headers)
    return res
  },
  async del(url, body, headers) {
    const res = await ajax('delete', url, body, headers)
    return res
  },
}

由于使用了环境变量 NODE_ENV

# 安装
npm install cross-env --save-dev

修改脚本

"script": {
    "test:local": "cross-env NODE_ENV=local jest --runInBand --passWithNoTests --colors --forceExit",
    "test:remote": "cross-env NODE_ENV=remote jest --runInBand --passWithNoTests --colors --forceExit"
}

创建测试文件 user-check.js

const { get } = require('./_server')

it('users/bar 测试', async () => {
  const { text, status } = await get('/users/bar')
  expect(status).toBe(200)
  expect(text).toBe('this is a users/bar response')
})

在 apis 文件夹下创建 index.test.js

// 导入
require('./user-check')
# 执行
npm run test:local

提交前处理

使用 pre-commit + husky + lint-staged

# 安装
npm i pre-commit husky lint-staged --save-dev
# 初始化 husky
npm set-script prepare "husky install"
npm run prepare

在 package.json 中配置 lint-staged

{
    "lint-staged": {
        "*.js": [
            "npm run lint",
            "npm run test:local"
        ]
    }
}
# 如果没有安装 npx 命令
npm install -g npx
# 添加 pre-commit 配置
npx husky add .husky/pre-commit 'npx lint-staged "$1"'

随便修改一个 src 下的 .js 文件,用于测试

# 执行
git add .
git commit -m "测试 commit 前的代码检查"

会根据 lint-staged 配置的,检查 git 缓存,匹配 *.js 文件,然后执行脚本检查代码

# 推送
git push

参考

pre-commit - npm (npmjs.com)

lint-staged - npm (npmjs.com)

husky - npm (npmjs.com)

提交信息规范

使用 @commitlint

# 安装
npm install -g @commitlint/cli @commitlint/config-conventional

配置 husky

npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"

在跟目录下添加 commitlint.config.js 文件

module.exports = { extends: ['@commitlint/config-conventional'] }
# 测试
git add .
git commit -m "commitlint 测试"
# No staged files match any configured task.
# ⧗   input: commitlint 测试
# ✖   subject may not be empty [subject-empty]
# ✖   type may not be empty [type-empty]

# ✖   found 2 problems, 0 warnings
# ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint
# 提交格式
git commit -m <type>[optional scope]: <description>
类型描述
build编译相关的修改,例如发布版本、对项目构建或者依赖的改动
chore其他修改, 比如改变构建流程、或者增加依赖库、工具等
ci持续集成
docs文档修改
feat新特性、新功能
fix修复 bug
perf代码优化相关,比如提升性能、体验
refactor代码重构
revert回滚到上一个版本
style代码格式修改, 注意不是 css 修改
test测试相关,如测试用例修改
# 正确写法,注意分号后面的空格
git commit -m "feat: 增加 commitlint 功能"

参考

commitlint - Lint commit messages

npx 使用教程 - 阮一峰的网络日志 (ruanyifeng.com)

CLI (commitlint.js.org)

提交信息提示功能

使用 commitizen

# 全局安装 
npm install -g commitizen
# 安装配置
commitizen init cz-conventional-changelog --save-dev --save-exact
# 测试
git add .
# 使用 git cz 进行提交,然后根据提示,输入内容,便可
git cz
# 推送
git push

使用 cz-customizable 自定义提示内容

# 安装
npm install cz-customizable --save-dev
// 在 package.json 将 cz-conventional-changelog 的配置
"config": {
    "commitizen": {
        "path": "./node_modules/cz-conventional-changelog"
    }
}
// 更改为,不再使用 cz-conventional-changelog
"config": {
    "commitizen": {
        "path": "./node_modules/cz-customizable"
    }
}

在根目录下创建 .cz-config.js

cz-customizable/cz-config-EXAMPLE.js at master · leoforfree/cz-customizable (github.com)

// 这里使用的是样例的配置,可根据需要自定义
module.exports = {
  types: [
    { value: 'feat', name: 'feat:     A new feature' },
    { value: 'fix', name: 'fix:      A bug fix' },
    { value: 'docs', name: 'docs:     Documentation only changes' },
    {
      value: 'style',
      name:
        'style:    Changes that do not affect the meaning of the code\n            (white-space, formatting, missing semi-colons, etc)',
    },
    {
      value: 'refactor',
      name: 'refactor: A code change that neither fixes a bug nor adds a feature',
    },
    {
      value: 'perf',
      name: 'perf:     A code change that improves performance',
    },
    { value: 'test', name: 'test:     Adding missing tests' },
    {
      value: 'chore',
      name:
        'chore:    Changes to the build process or auxiliary tools\n            and libraries such as documentation generation',
    },
    { value: 'revert', name: 'revert:   Revert to a commit' },
    { value: 'WIP', name: 'WIP:      Work in progress' },
  ],

  scopes: [{ name: 'accounts' }, { name: 'admin' }, { name: 'exampleScope' }, { name: 'changeMe' }],

  allowTicketNumber: false,
  isTicketNumberRequired: false,
  ticketNumberPrefix: 'TICKET-',
  ticketNumberRegExp: '\\d{1,5}',

  // it needs to match the value for field type. Eg.: 'fix'
  /*
  scopeOverrides: {
    fix: [
      {name: 'merge'},
      {name: 'style'},
      {name: 'e2eTest'},
      {name: 'unitTest'}
    ]
  },
  */
  // override the messages, defaults are as follows
  messages: {
    type: "Select the type of change that you're committing:",
    scope: '\nDenote the SCOPE of this change (optional):',
    // used if allowCustomScopes is true
    customScope: 'Denote the SCOPE of this change:',
    subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
    body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
    breaking: 'List any BREAKING CHANGES (optional):\n',
    footer: 'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n',
    confirmCommit: 'Are you sure you want to proceed with the commit above?',
  },

  allowCustomScopes: true,
  allowBreakingChanges: ['feat', 'fix'],
  // skip any questions you want
  skipQuestions: ['body'],

  // limit subject length
  subjectLimit: 100,
  // breaklineChar: '|', // It is supported for fields body and footer.
  // footerPrefix : 'ISSUES CLOSED:'
  // askForBreakingChangeFirst : true, // default is false
};

参考

cz-customizable - npm (npmjs.com)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值