Files
STM32F4-Base/scripts/check_ui_golden.py
T
wandering1 44dec5c49b feat(UI): golden 像素回归入提交门禁(W6 U4 第三件,35→36 钩子)
补上我上一轮自己标记为 2/3 的那块缺口:两个 golden 脚本早已存在且一直在
人工跑,但**从未进自动门禁**——"有基线"不等于"有门禁"(§6.1 原文即自认)。

## 先实测成本再定形态
改一个 UI 源文件后「增量重编模拟器 + 两条 golden」合计 **2~4 秒**,支持走
自动门禁。若实测要几分钟,正确做法是明确不挂、改为文档化人工门禁——一个
逼人 --no-verify 的门禁等于没有门禁,故这个数字是本决定的前提而非附注。

## 落地
新增 scripts/check_ui_golden.py:串「增量构建 → 菜单 8 状态 → 内容页 11 页
+ 池水位」。**有意忽略 argv 且 pass_filenames: false**——两条 golden 按整棵
菜单树 + 全量参考图工作,不接受文件参数,pre-commit 传的变更名对它无意义。
files: 覆盖 UI 源 + ui_task.{c,h} + 模拟器 tests/sim/src + main.c +
CMakeLists + lv_conf.h + 包装器与本配置自身(pre-commit 4.x 无 always: true,
files 是唯一触发手段)。

## 端到端验的是钩子,不是脚本
干净树连跑 3 次 rc=0 全 Passed;给 ui_page_dc.c 的 .top_y 注入 +5 位移 →
**钩子 Failed** 并点名 `[dc] FAIL 与参考页不一致(1882 px 差异)`;还原后
git diff 干净、simulator/tests/ref 的 git status 为空——**全程未用 --update
刷基线**(那正是本钩子要防的行为)。
诚实记录瑕疵:首次实测在"连续注入/还原的紧邻重建"之间偶发失败一次,疑似
MSBuild 节点争用,此后 3 次连跑均绿。已把"单次失败先复跑、连续两次才当真、
不许直接 --no-verify 绕过"写进钩子注释。

## 文档同步
AGENTS.md 钩子数与文末索引 35→36 + 钩子清单补 ui-golden;
pre-commit使用说明.md 概览计数同步;报告 §6.5 U4 由 2/3 → **3/3**(这次是
"真进了自动门禁",不是"脚本存在")、§6.1 golden 行转 ✅、§0.1 缺口描述更新。

## W6 剩余
U2 合并两页记录、U5 落地目标页(须先对齐"目标页 vs 现存 7 个 ui_page_*.c"
的差集——报告的"27 页"是目标数而非现状数)。
2026-10-20 22:14:42 +08:00

60 lines
1.9 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称:UI 像素回归门禁包装器
模块功能:把模拟器增量构建 + 菜单/内容页两条 golden 回归串成单个 pre-commit 钩子
适用范围:提交门禁(仅 UI 源变更时触发,见 .pre-commit-config.yaml 的 files 白名单)
说明:pre-commit 会把本次变更的文件名作为参数传给钩子,而两条 golden 脚本是按
"整棵菜单树 + 全量参考图"工作的、不接受文件参数,故本包装器**有意忽略** argv,
只做"是否需要跑"的门禁适配与退出码传递。
作者:王建锋
创建日期:2026-10-20
修改记录:
2026-10-20 王建锋 创建(W6 U4 收尾:golden 入提交门禁)
"""
import os
import subprocess
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BUILD_BAT = os.path.join(ROOT, 'simulator', 'build_sim.bat')
PY = sys.executable
CHECKS = [
os.path.join('simulator', 'tests', 'check_menu_rows.py'),
os.path.join('simulator', 'tests', 'check_content_pages.py'),
]
def run(cmd):
"""执行一条命令,透传输出,返回退出码。
参数:cmd - 命令列表 list[str]
返回值:子进程退出码 int
"""
return subprocess.call(cmd, cwd=ROOT)
def main():
"""先增量构建模拟器,再依次跑两条 golden 回归。
返回值:0 - 全部一致;1 - 任一环节失败(失败详情由被包装脚本自己打印) int
"""
print('[ui-golden] 增量构建模拟器 ...')
if run([BUILD_BAT]) != 0:
print('[ui-golden] FAIL 模拟器构建失败,无法做像素回归')
return 1
rc_all = 0
for rel in CHECKS:
print('[ui-golden] 跑 %s ...' % rel)
rc = run([PY, os.path.join(ROOT, rel)])
if rc != 0:
print('[ui-golden] FAIL %s 退出码 %d' % (rel, rc))
rc_all = 1
return rc_all
if __name__ == '__main__':
sys.exit(main())