真值三源互证:YAML 解析条目数 51(仓库口径的自查命令)、带 stages:[manual] 的 3 根、AGENTS.md 的 「共 51 个钩子 / 提交期实跑 48 根」、门禁说明 README 的「声明的 51」与「51 个 hook → 28 篇」、 pre-commit 使用说明的「51 声明数,一次 git commit 实跑 48 根」——全部一致,唯一离群值就是方案文档 那条表格行里的 31;而同一份文档第 22 行自己写着 51,属文档内部自相矛盾,这是最硬的判据。 :248 取 51 而不是 48:该行主语是 ci_local,本次实跑日志实证它覆盖静态 passed=47 + manual 三根 rc=0 + gitlint 十条,正好是声明的 51 根全跑;48 是「一次 git commit 实跑」的口径(47 静态 + gitlint), 两个数分列、不许混写。同时把裸数字改成带出处指向的写法,下次加钩子这里少一个查不到来源的数。 远程CI 指南那处只加「当时」两个字:26 是 2026-10-12 那次 gitlint 环境事故的观测值,数字本身不算错, 但句子是现在语气,会被读成今天静态段的条数(现 47)。按计数同步 playbook 的最小动作加注,不重述数字。 冻结并写明类别:pre-commit 使用说明的「当时 40 个 hook」、主机单测覆盖率口径的 39/16(句中已有 「当时」);同数不同义不动——run_boot_test.py 的「31 份 boot_log」是日志份数、verify_log.py 的 rec[31:59] 是字节偏移;命中面之外不动——.venv/ 与 Lib/ 第三方、.git/ 内的 stray 报告。 邻族实测自洽、本轮未碰:22 根专属钩子 + 19 套无专属 = 41 套、28 篇索引、51/48/47 三分列。 门禁:编号门禁 [OK];doc-links --all --sections-strict RC=0(2602 处引用、无法判定 0、194 文档, 章节引用 +1 就是新增的这处 §2 指向);两文件无 BOM、CR=0、无 U+FFFD、无行尾空格、结尾单 LF、 表格仍为 5 列;旧形态复扫「31 钩子 / 31 个钩子 / 31钩子」全仓命中 0。改动不落体积门禁指纹面, 不需要 @build。
远程 CI(Gitea Actions)—— 本目录是唯一入口
适用范围(先读这句,可以省下很多时间) 本仓库的远程 CI 只跑在本机这一台 runner 上:runner 名
win-stm32-ci,装在D:\Docker\act_runner,连的是本机原生 Giteahttp://127.0.0.1:3001。 其他机器、其他项目都不涉及,也不需要配这套东西。日常改代码不需要读本目录:提交前的等价自查是本地门禁,runner 在不在线都照样跑——
& '.venv\Scripts\python.exe' scripts/ci_local.py # 静态门禁 + 提交信息门禁 + 主机侧纯逻辑单测只有在这三种情况下才需要进来:① 换机/重装后要重新部署 runner;② CI 不出任务或莫名 取消;③ 改
.gitea/workflows/ci.yml本身。
索引
全部内容是一篇文档:远程CI完整指南.md(2026-10-12 由原「环境与部署」
目录下的两篇指南 CI配置指南.md 与 Gitea_Runner部署指南.md 合并而来,两篇均已删除,
去重后为单一来源)。
| 想干什么 | 去看 |
|---|---|
| 先搞清 CI 需要哪三样东西就位、本机拓扑、部署前置清单 | §0 / §0.1 / §0.2 |
| CI 体积门禁现在怎么守(同码凭证强制,「只声明不执行」那处盲区已关闭;gitlint 空转仍在) | §0.0 + §7 排障表"钩子条数对不上"行 |
服务端开启 Actions、DEFAULT_ACTIONS_URL 到底管什么 |
§1(含 §1.2.1,这条最容易搞反) |
下载 / 注册 runner(--instance 用回环、labels 必须精确匹配 runs-on) |
§2.2 |
config.yaml 各字段语义(capacity / timeout / labels / 日志目录…) |
§2.3 |
| 常驻:为什么必须看门狗、不能只起 daemon、也不能做成 Windows 服务 | §2.4 + §3.0 |
runner 装什么软件、为什么变量必须对 SYSTEM 可见、机器级 DTU_* |
§4(§4.1.1~§4.1.3 是三个真坑) |
workflow 位置 / 触发 / 内网拉不到 actions/checkout 的三种处置 |
§5(§5.3 零依赖写法) |
| 两个 job 各自跑哪些步骤、两条 Python 探测链要同序同步 | §5.5 |
| 端到端验证清单、无网页登录时直查 MySQL 核验 | §6 / §6.1 |
出问题了按症状查表(含 0x41301、1053、72h 被杀、.ps1 无 BOM 乱码…) |
§7 |
| 日常维护(改钩子集 / 改 workflow 后要不要动 runner) | §8 |
| 一键自检脚本、最小操作清单 TL;DR | §9 / §10 |
常用命令速查
# 本地等价门禁(不依赖 runner,日常用这个)
& '.venv\Scripts\python.exe' scripts/ci_local.py
# runner 体检(四项:计划任务 / 进程 / Gitea 可达 / 机器级变量)—— 须管理员
& '.\scripts\ci_runner_bootstrap.ps1' -Status
# 干跑:只打印将要写入的启动器与任务对象,不落盘不注册(免管理员)
& '.\scripts\ci_runner_bootstrap.ps1' -DryRun
# 部署 / 修复:写机器级 DTU_* + 生成看门狗启动器 + 注册开机计划任务 + 立即启动(须管理员)
& '.\scripts\ci_runner_bootstrap.ps1' -SetEnv -StartNow
⚠️ 上面三条
ci_runner_bootstrap.ps1是本机运维动作,会改系统计划任务与机器级环境 变量;返回码0x41301是"任务正在运行"、next run为空是开机触发器的正常表现, 都不是故障(详见指南 §3.4)。
✅ 机器侧遗留已清理(2026-10-12):旧方案的
deploy_runner_task.ps1与run_runner.cmd已从D:\Docker\act_runner\删除(它们跑单次 daemon,首次 Declare 失败就永久停摆, 机理见指南 §3.2;check_env.ps1里指向它们的提示也已改指 bootstrap)。 现行部署只有ci_runner_bootstrap.ps1这一条路。
🔴 重跑部署前先知道这条(2026-10-12 实测):
Unregister-ScheduledTask不会带走旧实例 启动的进程。旧看门狗会作为孤儿继续养着它的 daemon,而那个 daemon 占着.runner.lock, 于是新看门狗每 10 秒失败一次(runner file is already locked by another process)—— 而 runner 在网页上照样显示 online,CI 看着正常,任务其实谁也没管。 现在-StartNow会先清掉这些残留进程再启动(约离线几秒),-Status也会报出重复实例。 2026-10-12 已实测收敛:清掉 3 个残留后daemon up: pid … (single instance), 监管链svchost(任务) → 看门狗 → daemon恢复,runner 回 online。
相关文档
- 测试分层与门禁决策(静态门禁~人工目检各层由谁把关):
../测试说明/测试开发标准流程.md - workflow 本体:
../../.gitea/workflows/ci.yml - 本地等价脚本:
../../scripts/ci_local.py - runner 机器的工具链环境要求:
../环境与部署/项目部署环境要求.md DTU_*工具路径变量机制:../环境与部署/本地工具路径环境变量方案.md
变更记录
(本文件不再记流水账:改了什么是正文说了算,改动过程查 git log。)