diff --git a/docs/测试说明/LVGL模拟器部署与使用说明.md b/docs/LVGL模拟器部署与使用说明.md similarity index 100% rename from docs/测试说明/LVGL模拟器部署与使用说明.md rename to docs/LVGL模拟器部署与使用说明.md diff --git a/docs/pre-commit使用说明.md b/docs/pre-commit使用说明.md new file mode 100644 index 00000000..da5938e0 --- /dev/null +++ b/docs/pre-commit使用说明.md @@ -0,0 +1,281 @@ +# pre-commit 自动化代码审查 — 部署与使用说明 + +> **生效前提**:本机已运行过 `pre-commit install`(钩子写入 `.git/hooks/`)。 +> 新机器/新开发者进入仓库后需执行一次 `pre-commit install`,详见「新机器启用」。 + +--- + +## 1. 部署架构 + +``` +git commit + └─ pre-commit(.git/hooks/pre-commit) + ├─ trailing-whitespace 自动修复行尾空格 + ├─ end-of-file-fixer 自动修复文件尾换行 + ├─ check-added-large-files 阻止 >1MB 大文件 + ├─ check-merge-conflict 阻止含冲突标记的文件 + ├─ check-yaml 校验 YAML 语法 + ├─ cppcheck C 静态分析(自有代码) + └─ no-mojibake 阻止 U+FFFD 乱码文件 + └─ commit-msg(.git/hooks/commit-msg) + └─ gitlint 校验 commit message 格式 +``` + +**两阶段钩子**:`pre-commit` 阶段拦截代码问题,`commit-msg` 阶段拦截格式问题。任一失败 → commit 中止。 + +### 依赖清单 + +| 组件 | 安装方式 | 用途 | +|---|---|---| +| pre-commit 4.6.2 | `uv tool install pre-commit` | 钩子框架 | +| cppcheck 2.21.0 | `winget install cppcheck` | C 静态分析引擎 | +| scripts/check_mojibake.py | 随仓库提交 | U+FFFD 乱码检测(纯 Python,无依赖) | + +> **PATH 要求**:cppcheck 安装后需在系统 PATH 中(`C:\Program Files\Cppcheck`)。winget 自动写入 User PATH,但当前终端不会立即生效,需**重开终端**。 + +--- + +## 2. 各钩子规则详解 + +### 2.1 trailing-whitespace — 行尾空格清理 + +| 项 | 说明 | +|---|---| +| **触发条件** | 文件任意行末尾含空格或 Tab | +| **处理方式** | **自动修复**(直接改写文件,删除行尾空白) | +| **影响范围** | 所有被 git 跟踪的文件 | +| **典型报错** | `Trim Trailing Whitespace` → `Fixing path/to/file.c` | +| **修复方式** | 无需手动修复,钩子已自动改写;重新 `git add` 即可 | + +> **注意**:首次对全库运行时,可能批量修改大量文件的行尾空格。这是正常行为,不会改变代码逻辑。 + +### 2.2 end-of-file-fixer — 文件尾换行 + +| 项 | 说明 | +|---|---| +| **触发条件** | 文件最后一行不是换行符(`\n`) | +| **处理方式** | **自动修复**(在文件尾部追加换行) | +| **典型报错** | `Fix End of Files` → `Fixing path/to/file.c` | +| **修复方式** | 无需手动修复,钩子已自动改写;重新 `git add` 即可 | + +### 2.3 check-added-large-files — 大文件拦截 + +| 项 | 说明 | +|---|---| +| **触发条件** | 单个文件 > 1MB(默认阈值) | +| **处理方式** | **阻止提交**(需手动修复) | +| **典型报错** | `ilerge file added: path/to/file.bin` | +| **修复方式** | 确认文件是否应提交;若为构建产物则加入 `.gitignore`,若为必要大文件用 `--no-verify` 跳过 | + +### 2.4 check-merge-conflict — 冲突标记拦截 + +| 项 | 说明 | +|---|---| +| **触发条件** | 文件含 `<<<<<<<`、`=======`、`>>>>>>>` 冲突标记 | +| **处理方式** | **阻止提交** | +| **修复方式** | 手动解决冲突后重新提交 | + +### 2.5 check-yaml — YAML 语法校验 + +| 项 | 说明 | +|---|---| +| **触发条件** | `.yaml` / `.yml` 文件语法错误 | +| **处理方式** | **阻止提交** | +| **检查对象** | 主要校验 `.pre-commit-config.yaml` 本身 | +| **修复方式** | 修正 YAML 缩进或语法后重新提交 | + +### 2.6 cppcheck — C 静态分析 + +| 项 | 说明 | +|---|---| +| **触发条件** | C 文件含 warning / performance / portability 级别缺陷 | +| **处理方式** | **阻止提交** | +| **扫描范围** | `App/`、`Src/`、`Inc/`、`Drivers/BSP/` 下的 .c 文件(排除第三方库) | +| **已知抑制** | `missingInclude`、`invalidPrintfArgType_sint/uint`(项目安全使用,非真正缺陷) | +| **典型报错** | `path/to/file.c:42: warning: ...` | +| **修复方式** | 根据 cppcheck 报告修复代码缺陷;若为误报可在 `.pre-commit-config.yaml` 的 args 中添加 `--suppress=规则名` | + +**排除目录**(不参与 cppcheck 扫描): + +``` +Drivers/CMSIS/ # ARM CMSIS(第三方) +Drivers/STM32F4xx_HAL_Driver/ # ST HAL(第三方) +Drivers/BSP/UI/ # LVGL UI 层(第三方) +Drivers/BSP/NET/lftpd/ # LwIP FTP(第三方) +Drivers/BSP/dhara/ # NAND FTL(第三方) +Lib/ # LVGL 库 +Middlewares/ # FreeRTOS +MDK-ARM/ # Keil 工程文件 +test/ # 测试代码 +``` + +### 2.7 no-mojibake — U+FFFD 乱码拦截 + +| 项 | 说明 | +|---|---| +| **触发条件** | C 文件含 `EF BF BD`(U+FFFD 替换符,表示不可逆的编码损坏) | +| **处理方式** | **阻止提交**(不可逆,必须修复) | +| **检测原理** | `scripts/check_mojibake.py` 以二进制读取文件,检测 `0xEF 0xBF 0xBD` 字节序列 | +| **典型报错** | `U+FFFD replacement chars found (encoding corrupted, irreversible!): path/to/file.c` | +| **修复方式** | 从 git 历史中找到最后一个干净版本(`git log` + `git show HEAD~N:path/to/file.c > file.c`),手动恢复损坏区域 | + +**已知豁免**(`exclude` 配置): + +``` +Drivers/BSP/TPAFE5160/tpafe5160.c # 历史遗留乱码,待修复后取消豁免 +``` + +> ⚠️ **编码铁律**:U+FFFD 是不可逆损坏。若发现新文件出现 U+FFFD,必须排查写入方式(禁用 Get-Content / Set-Content 重写中文文件)。 + +### 2.8 gitlint — Commit Message 格式 + +| 项 | 说明 | +|---|---| +| **触发条件** | commit message 标题超 100 字符 / 含 body-is-missing 警告 | +| **处理方式** | **阻止提交**(commit-msg 阶段) | +| **当前规则** | 宽松:不强制 Conventional Commits,兼容中文标题 | +| **典型报错** | `T1 Title exceeds max length (159>100)` | +| **修复方式** | 精简 commit message 标题到 100 字符以内,或拆分为多行(标题+空行+body) | + +--- + +## 3. 日常工作流 + +### 3.1 正常提交(秒级完成) + +```bash +git add . +git commit -m "修复网络超时重连逻辑" +``` + +**全部钩子自动运行**,只检查本次 staged 的文件(增量扫描)。通常 <5 秒完成。 + +### 3.2 钩子失败后的处理 + +```bash +# 提交被拦截,查看报错信息 +# 修复后重新 add + commit +git add . +git commit -m "修复网络超时重连逻辑" +``` + +**常见失败场景与处理**: + +| 钩子 | 失败表现 | 处理步骤 | +|---|---|---| +| trailing-whitespace | `Fixing xxx.c` → 需要重新 `git add` | 钩子已自动修复文件,`git add` 后重新提交 | +| end-of-file-fixer | 同上 | 同上 | +| cppcheck | 报 warning/performance/portability | 根据报告修复代码,或在 args 中添加 `--suppress=规则名` | +| no-mojibake | `U+FFFD replacement chars found` | 从 git 历史恢复干净版本(不可逆!) | +| gitlint | `Title exceeds max length` | 精简 commit message 标题 | + +### 3.3 全库扫描(配置变更后) + +```bash +pre-commit run --all-files +``` + +仅在以下场景使用: +- 首次 `pre-commit install` 后确认基线 +- 修改 `.pre-commit-config.yaml` 后验证 +- `cppcheck` 新增 suppress 规则后验证 + +> 日常提交**不需要**跑 `--all-files`,pre-commit 会自动只检查 staged 文件。 + +### 3.4 手动运行单个钩子 + +```bash +pre-commit run cppcheck --all-files # 只跑 cppcheck +pre-commit run trailing-whitespace --files path/to/file.c # 只检查单个文件 +pre-commit run no-mojibake --files path/to/file.c +pre-commit run gitlint --hook-stage commit-msg --commit-msg-filename .git/COMMIT_EDITMSG +``` + +### 3.5 临时跳过钩子(紧急情况) + +```bash +git commit -m "紧急修复" --no-verify +# 或跳过特定钩子 +SKIP=cppcheck git commit -m "紧急修复" +``` + +> ⚠️ **不推荐**,仅用于紧急修复。跳过后的代码应在下一次提交中补上检查。 + +--- + +## 4. 新机器启用 + +```powershell +# 1. 安装 pre-commit(需要 uv) +uv tool install pre-commit + +# 2. 安装 cppcheck(需要 winget) +winget install cppcheck +# 重开终端使 PATH 生效 + +# 3. 进入仓库,安装钩子 +cd D:\Code\DTU Code\STM32F4-Base +pre-commit install + +# 4. 首次全库扫描(确认基线) +pre-commit run --all-files +``` + +--- + +## 5. 已知问题与注意事项 + +### 5.1 cppcheck 找不到 + +**现象**:`Executable cppcheck not found` + +**原因**:cppcheck 安装后 PATH 更新在注册表,已运行的终端不会刷新。 + +**解决**:重开终端即可。若需在当前会话临时修复: + +```powershell +$env:PATH = [Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [Environment]::GetEnvironmentVariable("Path","User") +``` + +### 5.2 tpafe5160.c 乱码 + +**状态**:已知历史遗留,HEAD(`e06d849`)已含 131 处 U+FFFD。no-mojibake 钩子已豁免该文件。 + +**修复计划**:从 `fe107ea`(干净版本)恢复注释区,完成后取消 `.pre-commit-config.yaml` 中的 `exclude` 条目。 + +### 5.3 LVGL 文档移动未提交 + +**状态**:工作区有 `docs/测试说明/LVGL模拟器部署与使用说明.md` 的删除(D)和 `docs/LVGL模拟器部署与使用说明.md` 的未跟踪(??),为用户历史操作,不在 pre-commit 管理范围内。 + +### 5.4 clang-format 未启用 + +**原因**:全库 222 个 .c/.h 文件大概率不满足 clang-format 默认格式,启用后会批量重写。 + +**计划**:Route B —— 全库统一格式化后形成独立基线 commit,再启用 clang-format 钩子。启用时取消 `.pre-commit-config.yaml` 中的注释即可。 + +--- + +## 6. 文件清单 + +| 文件 | 位置 | 说明 | +|---|---|---| +| `.pre-commit-config.yaml` | 仓库根 | 钩子配置(7 个钩子 + 1 个预留) | +| `.gitlint` | 仓库根 | gitlint 规则(宽松,兼容中文) | +| `scripts/check_mojibake.py` | scripts/ | U+FFFD 检测脚本 | +| `docs/自动化代码审查实施.md` | docs/ | 实施规划文档(Route A/B 设计) | +| `docs/测试说明/pre-commit使用说明.md` | 本文档 | 部署与使用说明 | + +--- + +## 7. 快速参考卡片 + +``` +提交代码: git add . && git commit -m "描述" +全库扫描: pre-commit run --all-files +单钩子扫描: pre-commit run --all-files +扫描单个文件: pre-commit run --files +跳过钩子: git commit --no-verify (紧急) +查看已安装钩子: ls .git/hooks/ +卸载钩子: pre-commit uninstall +更新钩子版本: pre-commit autoupdate +``` diff --git a/docs/自动化代码审查实施.md b/docs/自动化代码审查实施.md deleted file mode 100644 index 912c7027..00000000 --- a/docs/自动化代码审查实施.md +++ /dev/null @@ -1,179 +0,0 @@ -# 自动化代码审查实施(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