Baseline 工作流
baseline 是某一时刻所有 finding 的快照。cha analyze --baseline <path> 会把这份快照里的 finding 过滤掉,CI 只对快照之后才出现的 finding 失败。
这一篇是日常节奏:怎么生成、怎么对比、什么时候刷。
生成
在主干上跑一次,时机选在团队明确"这些都先放着"的那一刻:
cha baseline
默认落到 .cha/baseline.json。要换位置用 -o:
cha baseline -o .cha/legacy-2026-Q1.json
文件本身是一组指纹——(路径, smell 名, 归一化后的位置)。位置之所以"归一化"是因为行号小幅移动时仍要能匹配(多加几行注释不应该让 finding "复活")。文件体积小、diff 友好,commit 进仓。
git add .cha/baseline.json
git commit -m "Cha baseline at adoption"
CI 里使用
cha analyze --baseline .cha/baseline.json --fail-on warning
baseline 里的指纹静默放过,其他 finding 正常报。新 finding 出现在改动行 → CI 失败;老 finding 继承下来 → CI 安静通过。
GitHub Actions step:
- name: cha
run: cha analyze --baseline .cha/baseline.json --fail-on warning
对比
过几周看一下变了什么:
cha baseline -o /tmp/now.json
diff -u .cha/baseline.json /tmp/now.json | less
- 行(baseline 里有、现在没有)表示这条 finding 不见了——技术债还掉了。+ 行(现在有、baseline 里没有)正常情况下不会出现;如果出现,说明 CI 里的 --baseline 没生效,去查配置。
刷新
团队还了足够多的 debt、原 baseline 大半已经过时之后,重新生成:
cha baseline # 覆盖 .cha/baseline.json
git diff .cha/baseline.json # 看少了哪些
git commit -am "Refresh Cha baseline (-32 entries)"
刷新可以按节奏(每季度是常见选择),或者在大重构落地后做一次。commit message 里写清楚少了多少条——这是个能在团队回顾会上拿出来讲的真实数字。
多 package
monorepo 里每个 package 一份 baseline:
for pkg in packages/*/; do
( cd "$pkg" && cha baseline )
done
每份 .cha/baseline.json 跟对应 package 放一起,CI 按 package 跑。详见 Monorepo CI。
baseline 不解决的事
- 规则错了 —— 如果某条 smell 一直在你不关心的代码上炸出来,别把它埋进 baseline。要么在
.cha.toml里调阈值,要么在那一处用 行内指令,要么把整条插件enabled = false。 - 指纹漂移(drift) —— baseline 屏蔽的是已有 finding 的指纹。新写的代码即使出了形态完全相同的 finding,只要指纹不一字不差地命中现有条目,照样会报。换句话说 baseline 不是"silence smell × file"那种粗粒度规则,它认的是具体那一处。