前提概要
我们使用<font style="color:rgb(77, 77, 77);">husky</font>
检测<font style="color:rgb(77, 77, 77);">git</font>
钩子,<font style="color:rgb(77, 77, 77);">lint-staged</font>
规范化暂存区代码,<font style="color:rgb(77, 77, 77);">commitlint</font>
规范化提交信息。
钩子介绍
git钩子 | 描述 | |
---|---|---|
pre-commit | 判断提交的代码是否符合规范 | |
commit-msg | 判断 commit 信息是否符合规范 | |
pre-push | 执行测试,避免对以前的内容造成影响 |
工具介绍
<font style="color:rgb(51, 51, 51);">husky</font>
:操作git钩子的工具<font style="color:rgb(51, 51, 51);">lint-staged</font>
:本地暂存代码检查工具<font style="color:rgb(51, 51, 51);">commitlint</font>
:提交信息校验工具<font style="color:rgb(51, 51, 51);">commitizen</font>
:辅助提交信息 ,全局安装后可以使用<font style="color:rgb(51, 51, 51);">cz</font>
命令,选项式提交<font style="color:rgb(51, 51, 51);">git</font>
commitlin
- 安装依赖
pnpm add @commitlint/config-conventional @commitlint/cli cz-git czg -D
- 使用的版本
"devDependencies": {
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"cz-git": "^1.10.1",
"czg": "^1.10.1"
},
- 说明
@commitlint/config-conventional
: 这是一个配置包,提供了一套基于 Angular 规范的提交信息格式规则。它帮助确保提交信息的一致性和可读性。
@commitlint/cli
:这是 Commitlint 的命令行工具,用于检查提交信息是否符合指定的规则。通常与 @commitlint/config-conventional 一起使用。
cz-git
: 这是一个 Commitizen 适配器,提供了一种交互式的方式来生成符合规范的提交信息。它可以帮助开发者在提交代码时选择合适的提交类型、描述和其他信息。
czg
: 这是一个命令行工具,类似于 cz-git,提供了一个交互式的界面来生成提交信息。它通常用于简化和标准化提交信息的创建过程。
package.json
更新相关代码
{
"scripts": {
"commit": "czg"
},
"commitizen": {
"path": "node_modules/cz-git"
}
}
- 简洁版本 -
commitlint.config.cjs
const fs = require('fs');
const path = require('path');
/** @type {import('cz-git').UserConfig} */
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',
[
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'build',
'ci',
'chore',
'revert',
'wip',
'workflow',
'types',
'release'
]
]
},
prompt: {
messages: {
type: '选择你要提交的类型 :',
scope: '选择一个提交范围[可选]:',
customScope: '请输入自定义的提交范围 :',
subject: '请简要描述提交 :\n',
body: '填写更加详细的变更描述[可选]。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更[可选]。使用 "|" 换行 :\n',
footerPrefixsSelect: '选择关联issue前缀[可选]:',
customFooterPrefixs: '输入自定义issue前缀 :',
footer: '列举关联issue [可选] 例如: #31, #I3244 :\n',
confirmCommit: '是否提交或修改commit ?'
},
types: [
{ value: 'feat', name: 'feat: ✨ 新增功能', emoji: '✨' },
{ value: 'fix', name: 'fix: 🐛 修复缺陷', emoji: '🐛' },
{ value: 'docs', name: 'docs: 📝 文档变更', emoji: '📝' },
{
value: 'style',
name: 'style: 💄 代码格式',
emoji: '💄'
},
{
value: 'refactor',
name: 'refactor: 🔨 代码重构',
emoji: '🔨'
},
{ value: 'perf', name: 'perf: ⚡️ 性能优化', emoji: '⚡️' },
{
value: 'test',
name: 'test: ✅ 测试',
emoji: '✅'
},
{
value: 'build',
name: 'build: 📦️ 打包构建',
emoji: '📦️'
},
{ value: 'ci', name: 'ci: 👷 CI 配置变更', emoji: '👷' },
{ value: 'revert', name: 'revert: ⏪️ 代码回退', emoji: '⏪️' },
{
value: 'chore',
name: 'chore: 🚀 构建/工程依赖/工具',
emoji: '🚀'
},
{ value: 'wip', name: 'wip: 🚧 正在开发中', emoji: '🚧' },
{ value: 'workflow', name: 'workflow: 🎯 工作流程改进', emoji: '🎯' }
],
useEmoji: true,
scopes: [],
customScopesAlign: 'bottom',
emptyScopesAlias: 'empty',
customScopesAlias: 'custom',
allowBreakingChanges: ['feat', 'fix'],
skipQuestions: ['scope', 'body', 'breaking', 'footerPrefix', 'footer'] // 自定义选择指定的问题不显示
}
};
- 注释版本 -
commitlint.config.cjs
// @see: https://cz-git.qbenben.com/zh/guide
const fs = require('fs');
const path = require('path');
const scopes = fs
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name.replace(/s$/, ''));
/** @type {import('cz-git').UserConfig} */
module.exports = {
ignores: [(commit) => commit.includes('init')],
extends: ['@commitlint/config-conventional'],
rules: {
// @see: https://commitlint.js.org/#/reference-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',
[
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'build',
'ci',
'chore',
'revert',
'wip',
'workflow',
'types',
'release'
]
]
},
prompt: {
messages: {
type: '选择你要提交的类型 :',
scope: '选择一个提交范围[可选]:',
customScope: '请输入自定义的提交范围 :',
subject: '填写简短精炼的变更描述 :\n',
body: '填写更加详细的变更描述[可选]。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更[可选]。使用 "|" 换行 :\n',
footerPrefixsSelect: '选择关联issue前缀[可选]:',
customFooterPrefixs: '输入自定义issue前缀 :',
footer: '列举关联issue [可选] 例如: #31, #I3244 :\n',
confirmCommit: '是否提交或修改commit ?'
},
types: [
{ value: 'feat', name: 'feat: ✨ 新增功能', emoji: '✨' },
{ value: 'fix', name: 'fix: 🐛 修复缺陷', emoji: '🐛' },
{ value: 'docs', name: 'docs: 📝 文档变更', emoji: '📝' },
{
value: 'style',
name: 'style: 💄 代码格式',
emoji: '💄'
},
{
value: 'refactor',
name: 'refactor: 🔨 代码重构',
emoji: '🔨'
},
{ value: 'perf', name: 'perf: ⚡️ 性能优化', emoji: '⚡️' },
{
value: 'test',
name: 'test: ✅ 测试',
emoji: '✅'
},
{
value: 'build',
name: 'build: 📦️ 打包构建',
emoji: '📦️'
},
{ value: 'ci', name: 'ci: 👷 CI 配置变更', emoji: '👷' },
{ value: 'revert', name: 'revert: ⏪️ 代码回退', emoji: '⏪️' },
{
value: 'chore',
name: 'chore: 🚀 构建/工程依赖/工具',
emoji: '🚀'
},
{ value: 'wip', name: 'wip: 🚧 正在开发中', emoji: '🚧' },
{ value: 'workflow', name: 'workflow: 🎯 工作流程改进', emoji: '🎯' },
{ value: 'types', name: 'types: 🏡 类型定义文件修改', emoji: '🏡' }
],
useEmoji: true, // 是否开启 commit message 带有 Emoji 字符。
emojiAlign: 'center', // 设置 Emoji 字符 的 位于头部位置
themeColorCode: '', // 设置提示查询器主题颜色, cyan青色
scopes: [...scopes], // 自定义选择 模块范围 命令行显示信息
allowCustomScopes: true, // 是否在选择 模块范围 显示自定义选项(custom)
allowEmptyScopes: true, // 是否在选择 模块范围 显示为空选项(empty)
customScopesAlign: 'bottom', // 设置 选择范围 中 为空选项(empty) 和 自定义选项(custom) 的 位置
customScopesAlias: 'custom', // 自定义 选择范围 中 自定义选项(custom) 在命令行中显示的 名称
emptyScopesAlias: 'empty', // 自定义 选择范围 中 为空选项(empty) 在命令行中显示的 名称
upperCaseSubject: false, // 是否自动将简短描述(subject)第一个字符进行大写处理
markBreakingChangeMode: false, // 添加额外的问题重大变更(BREAKING CHANGES)提问,询问是否需要添加 "!" 标识于
allowBreakingChanges: ['feat', 'fix'], // 允许出现 重大变更(BREAKING CHANGES)的特定 type
breaklineNumber: 100, // 详细描述(body)和重大变更(BREAKING CHANGES)中根据字符超过该数值自动换行
breaklineChar: '|', // 详细描述(body)和重大变更(BREAKING CHANGES)中换行字符
skipQuestions: ['scope', 'body', 'breaking', 'footerPrefix', 'footer'], // 自定义选择指定的问题不显示
// 自定义选择issue前缀
issuePrefixs: [
// 如果使用 gitee 作为开发管理
{ value: 'link', name: 'link: 链接 ISSUES 进行中' },
{ value: 'closed', name: 'closed: 标记 ISSUES 已完成' }
],
customIssuePrefixsAlign: 'top', // 设置 选择 issue 前缀 中 跳过选项(skip) 和 自定义选项(custom) 的 位置
emptyIssuePrefixsAlias: 'skip', // 自定义 选择 issue 前缀 中 跳过选项(skip) 在命令行中显示的 名称
customIssuePrefixsAlias: 'custom', // 自定义 选择 issue 前缀 中 自定义选项(custom) 在命令行中显示的 名称
allowCustomIssuePrefixs: true, // 是否在选择 ISSUE 前缀 显示自定义选项(custom)
allowEmptyIssuePrefixs: true, // 是否在选择 ISSUE 前缀 显示为跳过选项(skip)
confirmColorize: true, // 确定提交中模板 commit message 是否着色
// maxHeaderLength: Infinity, // 定义commit message中的 header 长度, 给予在命令行中的校验信息
// maxSubjectLength: Infinity, // 定义commit message中的 subject 长度, 给予在命令行中的校验信息
minSubjectLength: 0, // 定义commit message中的 subject 长度, 给予在命令行中的校验信息
scopeOverrides: undefined, // 自定义选择了特定类型后 覆盖模块范围 命令行显示信息
defaultBody: '', // 在 详细描述 中是否使用显示默认值
defaultIssues: '', // 在 输入ISSUE 中是否使用显示默认值
defaultScope: '', // 如果 defaultScope 与在选择范围列表项中的 value 相匹配就会进行星标置顶操作。
defaultSubject: '' // 在 简短描述 中是否使用显示默认值
}
};
husky & lint-staged
- 安装依赖
pnpm add husky lint-staged -D
- 使用的版本
"devDependencies": {
"husky": "^9.1.6",
"lint-staged": "^15.2.10"
},
- 更新
package.json
"scripts": {
"prepare": "husky",
},
- 添加文件
.lintstagedrc
{
"*.{js,jsx,ts,tsx}": [
"pnpm run lint:fix"
],
"*.{css,scss}": [
"pnpm run stylelint:fix",
"git add"
]
}
- 或者
lint-staged.config.cjs
module.exports = {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": ["prettier --write--parser json"],
"package.json": ["prettier --write"],
"*.vue": ["eslint --fix", "prettier --write", "stylelint --fix"],
"*.{scss,less,styl,html}": ["stylelint --fix", "prettier --write"],
"*.md": ["prettier --write"]
};