巡检器(consistency checker,一致性检查器):把一批文件共同遵守的约定, 写成一条条可机器判定的规则 rule,一次跑完所有文件、逐条报出规则、位置与原因, 并把结论压在一个退出码 exit code 上的只读工具。它属于 静态检查 static analysis:只读文本,不运行内容,也不判断事实对不对。 就像小区保安每晚拿着同一张清单绕一圈:哪户门没关、哪盏灯不亮,连门牌号一起记在群里 —— 清单上没写的毛病,他那一圈也看不出来。
这类麻烦的共同点是:没有任何东西会因此报错,于是谁也没被提醒。
约定 什么算「讲道理」 -> 规则 每条只盯一个可判定的特征 -> 全量扫描 每次都从零重算 -> 报告 规则 · 文件:行号 · 原因 -> 退出码 0 是过,非 0 是不过 -> 流水线 自动拦下或放行
规则 · 文件:行号 · 原因,行号 0 表示整文件级的问题
(例如「没有任何地方引用它」)。位置是它比一句「有问题」有用的全部原因。本库自己也有一套这样跑的巡检器,常年守着库里的结构约定;它的规则清单属于库内部的事, 这里只讲这一类工具的通用形状。
场景一:提交前就拦住,别等推上去才发现。
pipx install pre-commit
pre-commit install # 装进 .git/hooks,以后每次 commit 前自动跑
pre-commit run --all-files # 现在手动对全库跑一遍
markdownlint "**/*.md" # 单跑一个:只管 Markdown 的排版(标题层级、空行、行宽)
lychee --offline "**/*.md" # 单跑一个:只查链接的目标还在不在,不联网
每个检查器各回一个退出码;只要有一个非 0,钩子就不放这次提交过去。pre-commit 负责 「什么时候跑」和「只跑改动过的文件」,判据仍然在各自的检查器手里。
场景二:每次推送,在干净机器上跑一遍,结果贴在 PR 上。
# .github/workflows/check.yml —— 文件名随便,关键是这几行
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pipx install pre-commit && pre-commit run --all-files
- run: lychee --offline --no-progress .
那台机器上没有你的本地状态:仓库是刚取的、检查器是新装的,跑出来的结论只看仓库里有什么 —— 这正是「每次都从零重算」想要的那个环境,也是它比「我记得跑一下」可靠的地方。
场景三:没有钩子也没有流水线,只想单独确认某一项。
markdownlint "docs/**/*.md" # 只查排版
lychee --offline --no-progress . # 只查链接
一次性用法:单独跑那个检查器、看它回的退出码 —— 0 是干净,非 0 就带着规则名与行号去改。 Markdown 的排版检查是最常见的一例,因为它的写法松、人也最容易写歪。
先问三句:它看单个文件内部,还是文件与文件之间?它管文档,还是管程序的行为? 它负责判定,还是只负责「什么时候跑」?
| 名称 | 它是什么 | 和本词什么关系 |
|---|---|---|
| 巡检器(一致性检查器) | 扫一批文件、看它们之间的结构关系:链接、引用、数量、归属 | 本课主角,管跨文件的那一层 |
| 格式检查器 linter | 只看单个文件内部的格式与排版:标题层级、空行、行宽 | 最容易被混为一谈的邻居:一个管这一页排得对不对,一个管这几页对得上对不对 |
| 链接检查器(如 lychee) | 专查一类关系:文档里每条链接的目标还在不在 | 巡检器的一个窄口径实例,只做了规则里的一条 |
| 测试夹具 | 造出一段可控的输入,看程序的行为等不等于预期 | 换了个对象:它判程序的行为,不判文件的结构 |
| CI / CD 流水线 | 每次推送时在干净机器上,把上面这几件事自动跑一遍 | 管「什么时候跑」;判据仍来自检查器自己的退出码 |
| pre-commit | 把检查挂在提交前的钩子上,不过就不许提交 | 把巡检器提前到本地:同一批规则,从推送后报警挪到提交前拦住 |
一句话分工:格式检查器管一页排得对不对,链接检查器管一条线通不通, 巡检器管整批文件对得上对不上,流水线与钩子只管「每次替我按一遍开关」。
三题自测,每题只有一个正确选项;选完立刻看到解释。
1. 巡检器能查出哪些问题,是由什么决定的?
对。覆盖面完全由写出来的规则决定:规则没写的关系,它一概不管 —— 所以「全绿」只能说明这一层过了, 说明不了内容对不对。
2. 一条规则反复报同一个老毛病,团队决定「先不管它」。这件事该落在哪份东西里?
对。已知的例外要显式写进白名单:它是一本「我知道它有、现在不修」的账。 薄薄一层没问题,厚起来就危险 —— 真问题会藏在里面,而报告看着越来越干净。
3. 想在「每次提交前」就拦住问题,而不是等推送之后才发现,靠什么?
对。pre-commit 这类工具把检查挂进提交前的钩子,不过就不许提交 —— 同一批规则, 只是在「什么时候跑」上往前挪了一步。