7.4 KiB
7.4 KiB
自动化代码审查实施(pre-commit 落地)
目标:在
git commit时自动执行「代码格式检查(只查不改写)→ 静态分析 → 乱码防护 → commit message 校验」,任一失败即中止提交。全部为本地 git 钩子,不依赖服务器;后续可扩展 Gitea Actions / PR-Agent(见文末「服务端扩展」)。
环境事实(已勘察,2026-08-31)
| 项 | 现状 | 影响 |
|---|---|---|
| Python | msys64 Python(无 pip)、WindowsApps 占位 python | 不能直接 pip install pre-commit |
uv |
C:\Users\Administrator\.local\bin\uv.exe ✅ |
用 uv 安装 pre-commit(参考项目自动报销系统同体系) |
| git | 2.55.0,core.autocrlf=true |
磁盘文件 CRLF、索引内 LF;钩子不启用 mixed-line-ending,避免换行翻转 |
| 源码编码 | 全库 222 个 .c/.h 均为 UTF-8 + CRLF(字节级验证,0 个 U+FFFD);docs/ 全部 UTF-8 | 当前无 GBK 文件,但规则仍以「只检查、不改写」为铁律 |
| 现有钩子 | 无(全为 .sample) | 从零安装,无冲突 |
| 需排除目录 | .opencode/node_modules/、Lib/lvgl/、simulator/、MDK-ARM/RTE/ |
钩子排除,否则误报/卡死 |
| winget | 可用 | 用于安装 cppcheck |
钩子选型(Route A 定稿)
| 钩子 | 来源 | 作用 | 状态 |
|---|---|---|---|
trailing-whitespace |
pre-commit-hooks v5.0.0 | 行尾空格(只删空白,编码安全) | ✅ 启用 |
end-of-file-fixer |
pre-commit-hooks | 文件尾换行 | ✅ 启用 |
check-added-large-files |
pre-commit-hooks | 防误提交大文件/构建产物 | ✅ 启用 |
check-merge-conflict |
pre-commit-hooks | 防提交未解决的冲突标记 | ✅ 启用 |
check-yaml |
pre-commit-hooks | 校验本配置自身 | ✅ 启用 |
clang-format |
mirrors-clang-format v19.1.4 | C 格式检查(--dry-run --Werror) |
⏸ Route A:先注释,暂不启用 |
gitlint |
jorisroovers/gitlint v0.19.1 | commit message 格式(宽松,兼容中文) | ✅ 启用(commit-msg 阶段) |
cppcheck |
local(需 winget 安装) | 静态分析 warning/performance/portability | ✅ 启用(未装可暂缓) |
no-mojibake |
local(scripts/check_mojibake.py) |
禁止 U+FFFD 乱码进入提交 | ✅ 启用 |
Route A 说明:全库 222 个文件大概率不满足 clang-format。本轮不启用 clang-format 钩子(配置保留注释),零破坏先跑起来;待以后全库统一格式化形成独立基线 commit 后再启用(见「路线 B(未来)」)。
阶段 0:安装 pre-commit(5 分钟)
uv tool install pre-commit
pre-commit --version
阶段 1:创建 .pre-commit-config.yaml(仓库根目录)
default_install_hook_types: [pre-commit, commit-msg]
exclude: |
(?x)^(
\.opencode/node_modules/|
Lib/lvgl/|
simulator/|
MDK-ARM/RTE/
)
repos:
# 1) 通用钩子(官方)
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-added-large-files
- id: check-merge-conflict
- id: check-yaml
# 2) C 代码格式:只检查,绝不改写(编码铁律)
# Route A:暂不启用,待全库格式化基线后再放开
# - repo: https://github.com/pre-commit/mirrors-clang-format
# rev: v19.1.4
# hooks:
# - id: clang-format
# args: [--dry-run, --Werror]
# 3) commit message 格式(宽松规则,兼容中文标题)
- repo: https://github.com/jorisroovers/gitlint
rev: v0.19.1
hooks:
- id: gitlint
# 4) 本地自定义钩子(仓库级)
- repo: local
hooks:
- id: cppcheck
name: cppcheck
entry: cppcheck
args: [--enable=warning,performance,portability, --error-exitcode=1,
--std=c99, --suppress=missingIncludeSystem, --quiet]
language: system
types: [c]
- id: no-mojibake
name: Forbid U+FFFD mojibake
entry: python scripts/check_mojibake.py
language: script
types: [c]
阶段 2:创建辅助文件
2.1 scripts/check_mojibake.py(UTF-8 编码)
import sys
BAD = b"\xef\xbf\xbd"
bad_files = []
for path in sys.argv[1:]:
with open(path, "rb") as f:
if BAD in f.read():
bad_files.append(path)
if bad_files:
print("U+FFFD replacement chars found:")
for p in bad_files:
print(" -", p)
sys.exit(1)
2.2 .gitlint(宽松规则)
[general]
ignore=body-is-missing
[title-max-length]
line-length=100
说明:不做 Conventional Commits 强制(现有"搭建LVGL仿真环境"这类中文标题必须能通过)。
2.3 .clang-format(预留,Route A 阶段创建但不启用)
按工程实际风格生成,以 4 空格缩进为基底(Keil 工程常见风格),启用 clang-format 时配套使用。
阶段 3:安装钩子 + 基线校准
pre-commit install # 同时安装 pre-commit 与 commit-msg 钩子
pre-commit run --all-files # 全库跑一遍,看当前违规
git commit提交首个版本(含.pre-commit-config.yaml、.gitlint、scripts/check_mojibake.py、本文档)。- 若
trailing-whitespace/end-of-file-fixer修改了文件,属正常:它们是白名单安全钩子(只删行尾空格、补尾部换行,不改编码)。
阶段 4:日常使用
- 提交时自动执行全部钩子,任一失败 → commit 中止,按提示修复后重新提交。
- 临时跳过单个钩子(逃生通道):
SKIP=cppcheck git commit -m "..."(不推荐)。 - 新机器启用:
uv tool install pre-commit→ 进入仓库 →pre-commit install。
路线 B(未来,待决策后执行)
全库统一格式化基线:
pre-commit run clang-format --all-files # 一次性格式化,独立 commit 提交
编码已验证全库 UTF-8,风险低;完成后放开 .pre-commit-config.yaml 中 clang-format 注释并强制。
服务端扩展(可选,后续)
- Gitea Actions(Gitea ≥1.19 自带,需管理员部署 runner):PR 上跑相同检查 +
@build编译(Windows runner 跑MDK-ARM/build.bat),结果回写 PR 状态。 - PR-Agent(12.8k★,官方支持 Gitea):
pip install pr-agent+ Gitea webhook,PR 自动 AI review。
风险与对策
| 风险 | 对策 |
|---|---|
| clang-format 改写触发乱码 | 只用 --dry-run --Werror,永不落盘;mojibake 钩子兜底 |
| CRLF/LF 因 autocrlf 混乱 | trailing-whitespace 只删空白不转换换行;不启用 mixed-line-ending |
| 全库格式化改动大 | Route A:clang-format 先注释,待基线 commit 再启用 |
| cppcheck 误报多 | --suppress 白名单收敛;先 warning/performance/portability 三档 |
| gitlint 卡中文提交 | 宽松配置,不强制 Conventional Commits |
| cppcheck 未安装导致钩子失败 | winget install cppcheck 安装并加入 PATH;或暂时注释该钩子 |
实施清单(Checklist)
- 阶段 0:
uv tool install pre-commit - 阶段 1:创建
.pre-commit-config.yaml - 阶段 2:创建
scripts/check_mojibake.py、.gitlint - 阶段 3:
pre-commit install+pre-commit run --all-files校准基线 - 验证:故意提交一条违规(行尾空格/坏 commit message/含 U+FFFD),确认被拦截
- 提交首个版本并推送到 Gitea