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

7.4 KiB
Raw Blame History

自动化代码审查实施(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 注释并强制。

服务端扩展(可选,后续)

  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