代码学习
通过 Commitizen 和 Commitlint 实现 Git 提交规范化,提升代码可读性、自动化发布流程并增强团队协作。包含 Docker 和二进制打包两种便捷配置方案。
代码学习
hello world
在软件开发中,规范化的提交信息可以显著提升代码质量和团队协作效率。什么是规范化的提交信息,请参考Conventional Commits。
为什么需要规范化提交信息?
使用规范化的提交信息有以下几个关键优势:
- 提高可读性 - 统一格式的提交信息使代码历史更易于理解和追踪
- 自动化发布 - 可基于提交类型自动生成版本号和更新日志
- 简化代码审查 - 清晰的提交目的使代码审查更加高效
- 增强团队协作 - 统一标准降低沟通成本,提高团队效率
- 方便筛选与查找 - 根据类型(如 feat, fix, docs)快速过滤相关提交
Conventional Commits 格式示例
符合规范的提交信息通常具有以下格式:
<类型>[可选作用域]: <描述>
[可选正文]
[可选脚注]
常见提交类型示例:
feat: 添加用户登录功能
fix: 修复移动端布局错位问题
docs: 更新API文档
style: 格式化代码样式
refactor: 重构用户认证模块
test: 添加购物车测试用例
chore: 更新构建脚本
为实现 Git 提交信息的规范化,常用的工具有 Commitizen 和 Commitlint。Commitizen 用于生成符合规范的提交信息,而 Commitlint 则用于检查提交信息是否符合规范。本文将介绍两款工具的 Docker 容器化配置以及使用 pkg 打包为二进制程序两种方式。而作为项目子模块安装的的配置方式请参考Commitizen 和 Commitlint官方提供的方法。
实现方式对比
以下是三种实现方式的对比:
| 实现方式 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| Docker容器 | 无需本地Node环境 环境隔离 团队统一配置 | 需要Docker环境 网络原因可能导致镜像构建失败 | 团队协作 CI/CD流水线 |
| 二进制打包 | 无需依赖 易于分发 启动快速 | 跨平台需单独打包 更新需重新打包 | 个人开发 无Node环境 |
| 项目安装 | 配置简单 易于定制 与项目绑定 | 每个项目需单独配置 需要Node环境 | 单个项目 定制化需求高 |
Docker 容器化配置
使用 Docker 容器化 Commitizen 和 Commitlint,可以在任何支持 Docker 的环境中运行,而无需担心 Node.js 环境的配置问题。
1. Dockerfile 配置
Dockerfile 是一个文本文件,包含了构建 Docker 镜像所需的所有指令。以下是一个示例 Dockerfile,用于配置 Commitizen 和 Commitlint:
FROM node:20-alpine
RUN apk add --no-cache git
RUN npm install -g commitizen cz-conventional-changelog
RUN npm install -g commitlint @commitlint/config-conventional
ARG USER_ID=1000
ARG GROUP_ID=1000
ARG USER_NAME=username
RUN addgroup -g ${GROUP_ID} ${USER_NAME} && \
adduser -D -u ${USER_ID} -G ${USER_NAME} ${USER_NAME}
RUN echo '{"path": "cz-conventional-changelog"}' > /home/${USER_NAME}/.czrc
RUN echo "export default { extends: ['@commitlint/config-conventional'] };" > /home/${USER_NAME}/commitlint.config.js
WORKDIR /repo
USER ${USER_NAME}
2. 构建 Docker 镜像
在项目根目录下创建一个名为 Dockerfile 的文件,并将上述内容复制到该文件中。然后在终端中运行以下命令构建 Docker 镜像:
docker build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g) --build-arg USER_NAME=$USER -t commit-tools -f Dockerfile .
3. 添加到 Git 钩子
Git 钩子是一些脚本,可以在特定的 Git 事件发生时自动执行。比如commit-msg 钩子可以在提交信息被输入时触发,而 prepare-commit-msg 钩子可以在提交消息准备好后触发。这两个钩子可以帮助我们在提交时自动生成规范的提交信息,并检查提交信息是否符合规范。为了在 Git 提交时自动使用 Commitizen 和 Commitlint,可以在项目中添加 Git 钩子,也可以使用 git config --global core.hooksPath 命令设置全局钩子路径,以便所有项目都可以使用不用重复配置。以下是如何配置 Git 钩子以使用 Commitizen 和 Commitlint 的示例。
commit-msg 钩子
在项目根目录下创建 .git/hooks/commit-msg 文件,并添加以下内容:
#!/bin/sh
docker run --rm -e FORCE_COLOR=true -v "$(pwd):/repo" commit-tools sh -c 'commitlint -g ~/commitlint.config.js --edit $1 --verbose'
prepare-commit-msg 钩子
在项目根目录下创建 .git/hooks/prepare-commit-msg 文件,并添加以下内容:
#!/bin/sh
commit_type="$2"
commit_msg_source="$3"
# 如果没有指定提交类型或提交消息来源,则使用 Commitizen 生成提交信息
if [ -z "$commit_type" ] && [ -z "$commit_msg_source" ]; then
exec < /dev/tty && docker run -it --rm -v "$(pwd):/repo" commit-tools sh -c 'cz -a --hook'
fi
exit 0
使用 pkg 打包为二进制程序
pkg 是一个可以将 Node.js 应用打包为独立可执行文件的工具。使用 pkg 可以将 Commitizen 和 Commitlint 打包为二进制程序,方便在没有 Node.js 环境的机器上运行。ncc 是一个用于将 Node.js 应用打包为单个文件的工具,适合用于打包小型应用或脚本。首先,确保您的系统上安装了 Node.js 和 npm。
分别创建 commitizen 和 commitlint 文件夹用于后期打包
1. 打包 commitizen
创建 cli.js 文件
在 commitizen 文件夹中创建一个 cli.js 入口文件,内容如下:
// cli.js
const fs = require('fs');
const path = require('path');
const { bootstrap } = require('commitizen/dist/cli/git-cz');
function handleError(error) {
console.error(error.message || error.toString());
}
process.on('uncaughtException', handleError);
process.on('unhandledRejection', handleError);
process.stdin.on('error', handleError);
process.stdout.on('error', handleError);
process.stderr.on('error', handleError);
try {
bootstrap({
cliPath: path.dirname(require.resolve('commitizen/package.json'))
});
} catch (error) {
handleError(error);
}
创建 package.json 文件
在 commitizen 文件夹中创建一个 package.json 文件,内容如下:
{
"name": "commitizen",
"version": "1.0.0",
"scripts": {
"build": "npx pkg cli.js --public --targets node18-linux-x64 --output dist/cz"
},
"devDependencies": {
"commitizen": "^4.3.1",
"cz-conventional-changelog": "^3.3.0"
},
}
打包和配置
在 commitizen 文件夹中运行以下命令:
npm install --no-fund
npm run build
在项目目录或者home目录下创建一个 .czrc 文件,内容如下:
{
"path": "cz-conventional-changelog"
}
也可以直接在package.json 中配置adapter 路径,如下:
"config": {
"commitizen": {
"path": "/snapshot/commitizen/node_modules/cz-conventional-changelog"
}
}
这里的 path 路径 /snapshot/commitizen/node_modules/cz-conventional-changelog 是因为 pkg 打包后,所有的依赖都会被打包到 /snapshot/commitizen 目录下。
2. 打包 commitlint
最新版本的 commitlint 是 ESM 模块,但是目前 pkg 对 ESM 模块的支持还不完善,因此需要使用旧版本的 commitlint, 最后一个对 cjs 支持友好的版本为18.6.1。以下是打包 commitlint 的步骤:
创建 cli.js 文件
在 commitlint 文件夹中创建一个 cli.js 入口文件,内容如下:
//cli.js
const path = require('path');
const { spawn } = require('child_process');
const args = process.argv.slice(2);
const cliPath = require.resolve('commitlint/cli');
const child = spawn(process.execPath, [cliPath, ...args], {
stdio: 'inherit',
shell: true,
cwd: process.cwd()
});
child.on('exit', (code, signal) => {
if (code !== null) {
process.exit(code);
} else if (signal) {
console.error(`${signal}`);
process.exit(1);
} else {
process.exit(0);
}
});
child.on('error', (err) => {
console.error(`${err.message}`);
process.exit(1);
});