1
0
Files
nex/openspec/specs/git-hooks/spec.md

168 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# git-hooks
## Purpose
定义仓库原生 Git hooks 的安装、校验、测试与跨平台执行规则,确保提交前快速检查和提交信息格式校验符合项目规范。
## Requirements
### Requirement: pre-commit hook 快速检查
pre-commit hook SHALL 在 `git commit` 执行前对 staged files 进行快速检查,仅检查本次提交涉及的文件。
#### Scenario: 无 Go 和前端文件变更时跳过
- **WHEN** staged files 中既无 `.go` 文件也无 `.ts`/`.tsx`/`.scss` 文件
- **THEN** pre-commit hook SHALL 直接通过,不运行任何 linter
#### Scenario: 冲突标记检测
- **WHEN** staged files 中包含 `<<<<<<<``=======``>>>>>>>` 冲突标记
- **THEN** pre-commit hook SHALL 报告错误并列出包含冲突的文件名
- **THEN** commit SHALL 被阻止
#### Scenario: Go 文件 lint 检查
- **WHEN** staged files 中包含 `.go` 文件
- **THEN** pre-commit hook SHALL 对 staged `.go` 文件运行 `golangci-lint run`(复用 `backend/.golangci.yml` 配置)
- **THEN** 若 lint 报告任何错误commit SHALL 被阻止
#### Scenario: 前端文件 lint 检查
- **WHEN** staged files 中包含 `.ts``.tsx` 文件
- **THEN** pre-commit hook SHALL 对 staged 前端文件运行 ESLint复用 `frontend/eslint.config.js` 配置)
- **THEN** 若 ESLint 报告任何错误commit SHALL 被阻止
#### Scenario: 前端文件格式检查
- **WHEN** staged files 中包含 `.ts``.tsx``.scss` 文件
- **THEN** pre-commit hook SHALL 对 staged 前端文件运行 Prettier 格式检查(复用 `frontend/.prettierrc` 配置)
- **THEN** 若存在格式不符合规范的文件commit SHALL 被阻止
#### Scenario: 大文件告警
- **WHEN** staged files 中存在超过 500KB 的文本文件
- **THEN** pre-commit hook SHALL 输出警告信息(不阻止提交),提示检查是否误提交
#### Scenario: commit 被阻止时显示修复提示
- **WHEN** pre-commit hook 检查失败
- **THEN** hook SHALL 输出明确的修复提示(如 `bun run fix`、手动解决冲突标记等)
### Requirement: commit-msg hook 校验提交信息格式
commit-msg hook SHALL 在 `git commit` 输入提交信息后校验格式,确保符合项目规范。提交描述 SHALL 使用中文;版本号、英文专有名词可与中文描述混用。
#### Scenario: 合法格式通过
- **WHEN** 提交信息首行格式为 `<类型>: <描述>`,类型为 `feat``fix``refactor``docs``style``test``chore` 之一
- **THEN** commit-msg hook SHALL 通过commit 正常执行
#### Scenario: 非法类型被拒绝
- **WHEN** 提交信息首行使用的类型不在允许列表中(如 `update: xxx`
- **THEN** commit-msg hook SHALL 报告错误显示允许的类型列表commit SHALL 被阻止
#### Scenario: 英文描述被拒绝
- **WHEN** 提交信息首行为 `feat: add auth`
- **THEN** commit-msg hook SHALL 报告错误,提示提交描述需使用中文
- **THEN** commit SHALL 被阻止
#### Scenario: 缺少冒号空格被拒绝
- **WHEN** 提交信息首行为 `feat:xxx`(冒号后无空格)或 `feat xxx`
- **THEN** commit-msg hook SHALL 报告格式错误commit SHALL 被阻止
#### Scenario: 首行过长告警
- **WHEN** 提交信息首行超过 72 个字符
- **THEN** commit-msg hook SHALL 输出警告(不阻止提交),提示首行应简短
#### Scenario: Merge commit 自动放行
- **WHEN** 提交信息首行以 `Merge` 开头
- **THEN** commit-msg hook SHALL 直接通过,不进行格式校验
#### Scenario: 格式错误时显示示例
- **WHEN** commit-msg hook 检查失败
- **THEN** hook SHALL 输出包含正确格式示例的错误信息(如 `feat: 添加供应商批量管理功能`
### Requirement: hooks-install 安装命令
`make hooks-install` SHALL 将 `scripts/git-hooks/` 下的 hook 脚本安装到 `.git/hooks/`,不覆盖 Git LFS 管理的 hook。
#### Scenario: 安装 pre-commit 和 commit-msg
- **WHEN** 执行 `make hooks-install`
- **THEN** `scripts/git-hooks/pre-commit` SHALL 被复制到 `.git/hooks/pre-commit`
- **THEN** `scripts/git-hooks/commit-msg` SHALL 被复制到 `.git/hooks/commit-msg`
- **THEN** 两个文件 SHALL 被设置为可执行(`chmod +x`
#### Scenario: 不覆盖 LFS 管理的 hook
- **WHEN** `.git/hooks/post-checkout``.git/hooks/post-commit``.git/hooks/post-merge``.git/hooks/pre-push` 已由 Git LFS 管理
- **THEN** `make hooks-install` SHALL NOT 覆盖或修改这些文件
#### Scenario: 重复安装幂等
- **WHEN** `make hooks-install` 被执行多次
- **THEN** hook 文件 SHALL 被正确覆盖更新,不会产生重复或损坏
#### Scenario: hooks-check 验证安装状态
- **WHEN** 执行 `make hooks-check`
- **THEN** 命令 SHALL 检查 `.git/hooks/pre-commit``.git/hooks/commit-msg` 是否存在且可执行
- **THEN** SHALL 输出每个 hook 的安装状态
### Requirement: hooks-test 回归测试命令
`make hooks-test` SHALL 运行仓库内 hook 回归测试,覆盖 commit-msg 格式校验和 pre-commit staged-file 检查,不污染真实 git index。
#### Scenario: 运行 hook 回归测试
- **WHEN** 执行 `make hooks-test`
- **THEN** SHALL 运行 `scripts/git-hooks/test-hooks.sh`
- **THEN** 测试 SHALL 使用临时 `GIT_INDEX_FILE` 构造 staged fixture
- **THEN** 若任一 hook 行为不符合预期,命令 SHALL 返回非零退出码
### Requirement: 跨平台可用
pre-commit 和 commit-msg hook 脚本 SHALL 可在 macOS 和 WindowsGit Bash上正常执行。
#### Scenario: macOS 上正常执行
- **WHEN** hook 脚本在 macOS 上被 git 调用
- **THEN** `#!/bin/sh` shebang SHALL 被系统正确解析
- **THEN** `exec make` SHALL 正确调用 Makefile target
#### Scenario: Windows Git Bash 上正常执行
- **WHEN** hook 脚本在 Windows 的 Git Bash 环境中被 git 调用
- **THEN** Git for Windows 自带的 sh.exe SHALL 正确解析 `#!/bin/sh`
- **THEN** `exec make` SHALL 正确调用 Makefile target依赖 Git Bash/MINGW64 环境中 `make` 可用)
- **THEN** Go 和 Bun 工具链 SHALL 通过 PATH 可被 Makefile 调用
### Requirement: pre-commit 核心逻辑在 Makefile 中复用
pre-commit hook 的检查逻辑 SHALL 通过 Makefile target 调用项目已有工具链,不重复实现 hook 框架逻辑。commit-msg hook SHALL 在脚本内直接完成格式校验。
#### Scenario: Go lint 复用后端配置
- **WHEN** pre-commit 需要检查 Go 文件
- **THEN** SHALL 调用 Makefile 逻辑,在 `backend/` 目录对 staged `.go` 文件运行 `go tool golangci-lint run`
- **THEN** SHALL 复用 `backend/.golangci.yml` 中的 lint 配置
#### Scenario: 前端 lint 使用 staged 文件参数
- **WHEN** pre-commit 需要检查前端文件
- **THEN** SHALL 调用 Makefile 逻辑,在 `frontend/` 目录对 staged 前端文件运行 ESLint 和 Prettier 的文件参数模式
- **THEN** SHALL NOT 在 pre-commit 阶段运行全量 `bun run check`
#### Scenario: 终端直接调试
- **WHEN** 开发者执行 `make _hooks-pre-commit`
- **THEN** SHALL 执行与 pre-commit hook 完全相同的检查逻辑
- **THEN** 输出 SHALL 与 hook 触发时一致