Files
STM32F4-Base/docs/自动化代码审查实施.md
T

180 lines
7.4 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.
# 自动化代码审查实施(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 分钟)
```powershell
uv tool install pre-commit
pre-commit --version
```
## 阶段 1:创建 `.pre-commit-config.yaml`(仓库根目录)
```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 编码)
```python
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`(宽松规则)
```ini
[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:安装钩子 + 基线校准
```powershell
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(未来,待决策后执行)
全库统一格式化基线:
```powershell
pre-commit run clang-format --all-files # 一次性格式化,独立 commit 提交
```
编码已验证全库 UTF-8,风险低;完成后放开 `.pre-commit-config.yaml` 中 clang-format 注释并强制。
## 服务端扩展(可选,后续)
1. **Gitea Actions**(Gitea ≥1.19 自带,需管理员部署 runner):PR 上跑相同检查 + `@build` 编译(Windows runner 跑 `MDK-ARM/build.bat`),结果回写 PR 状态。
2. **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