Shamefile 实战指南:让每个 Linter 绕过都有据可查
问题的起点:无声的技术债
在任何一个有一定规模的代码库中,你几乎都能找到这样的注释:
import some_very_long_module_name_that_exceeds_line_length
// eslint-disable-next-line @typescript-eslint/no-explicit-any const data: any = response.data;
@SuppressWarnings("unchecked")
List items = (List) rawList;
开发者按下这条”静音键”的理由往往五花八门——时间紧迫、第三方库的限制、暂时无法重构的遗留代码。但问题在于:没有人记录为什么这条警告被静音了。
时间一长,这些 // NOLINT、# noqa、@SuppressWarnings 就变成了无人能懂的神秘标记。代码评审时,评审者也没精力逐一检查每一处 linter 绕过是否合理。
这就是 Shamefile 要解决的问题——一个用 Rust 编写的 CLI 工具,强制开发者在绕过 linter 时记录原因,让无声的技术债变成可审查的决策记录。
Shamefile 核心思路
Shamefile 的工作方式很直接:
- 扫描代码库中所有的 linter 静音标记
- 将发现的绕过记录写入
shamefile.yaml - 要求每个条目都必须填写
why字段(为什么绕过) - 在 CI 中运行
shame me . --dry-run验证所有绕过都有理由
核心宗旨:可以绕过 linter,但必须有理由,而且理由要经得起代码审查。
快速上手
安装
Shamefile 支持多种安装方式:
npm install -g shamefile pip install shamefile cargo install shamefile cargo install --git https://github.com/BKDDFS/shamefile
安装后,运行 shame --help 确认一切正常。
初始化
在项目根目录运行:
shame me .
这会扫描当前目录下的所有源码文件,查找 linter 静音注释,并生成一个 shamefile.yaml 文件:
suppressions:
- file: "src/api/handler.py"
line: 42
tool: flake8
code: E501
token: "abc123"
why: "" # ← 空的,需要填写
- file: "src/components/Button.tsx"
line: 15
tool: eslint
code: "@typescript-eslint/no-explicit-any"
token: "def456"
why: "" # ← 空的,需要填写
每个绕过记录都有一个空的 why 字段——这就等着开发者去填。
填写理由
使用 shame next 命令逐一补充理由:
shame next shame next "第三方 API 返回 Union 类型,TypeScript 无法推断"
也可以在文本编辑器中直接编辑 shamefile.yaml。
集成到 CI
在 CI 流程中添加验证步骤:
shame me . --dry-run
如果存在任何未填写 why 的绕过,CI 将会失败——就像测试失败一样明确。
Pre-commit 钩子
对于使用 pre-commit 的项目,直接在配置中添加:
- repo: https://github.com/BKDDFS/shamefile
rev: main
hooks:
- id: shamefile
这样每次提交都会自动验证。
支持的语言和工具
Shamefile 支持主流的 linter 静音机制:
| 语言 | 静音机制 | 示例 |
|---|---|---|
| Python | # noqa | # noqa: E501 |
| JavaScript/TypeScript | // eslint-disable | // eslint-disable-next-line |
| Java | @SuppressWarnings | @SuppressWarnings("unchecked") |
| C# | #pragma warning disable | #pragma warning disable CS0168 |
| Go | //nolint | //nolint:gosec |
这意味着无论你的技术栈是什么,Shamefile 基本都能覆盖。
实际使用场景
场景一:遗留代码重构
接手一个老项目时,代码里散布着几十个 // eslint-disable。有了 Shamefile,你可以:
- 运行
shame me .一次性发现所有绕过 - 逐个评估——能修复的直接修复,不能修复的记下原因
- 在
shamefile.yaml中记录重构计划的时间线
- file: "legacy/parser.ts" line: 89 tool: eslint code: "@typescript-eslint/no-unsafe-assignment" token: "ghi789" why: "待 v3 重构后移除依赖的类型断言,跟踪 ISSUE-1234"
场景二:AI 编码工具的安全护栏
这是一个很有意思的应用场景。AI 编码工具(Claude Code、Cursor、GitHub Copilot)在生成代码时,经常因为 lint 检查不通过而自动添加 // eslint-disable 或 # noqa 注释。这些注释通常没有任何理由——AI 只是”知道”这样能通过检查,但并不理解为什么。
Shamefile 的 README 中特别提到这一点:AI Agent 也被迫要思考”这条警告真的不可修复吗?” 当 CI 因为 why 字段为空而失败时,无论是人类还是 AI,都必须给出合理的解释。
场景三:代码审查中的制衡
传统代码审查中,评审者很难注意到新增的 linter 绕过——它们在 diff 中不够显眼。有了 Shamefile:
- CI 会强制提交者填写理由
shamefile.yaml的变更在 PR diff 中一目了然- 评审者可以直接在 PR 中评论:”这个绕过理由不够充分,能修掉它吗?”
工作流程总结
提交代码 → 运行 pre-commit(Shamefile 检查)
↓
有未填写的绕过?→ 运行 shame next 填写理由
↓
提交 PR → CI 运行 shame me . --dry-run
↓
通过 → 代码评审(查看 shamefile.yaml diff)
↓
评审通过 → 合并
与同类工具的对比
与 git blame 或简单的 TODO 注释相比,Shamefile 的优势在于:
- 集中化:所有 linter 绕过的理由集中在一个 YAML 文件中,不需要在代码中四处搜寻
- CI 强制执行:空
why字段会导致 CI 失败,不像 TODO 注释那样会被忽略 - 可审查:每个绕过都有明确的上下文(文件名、行号、工具名、代码),评审者可以据此做出判断
- 持久化:知识留在 YAML 文件中,不会随着人员离职而消失
小结
Shamefile 解决的是一个微小但持久的问题——linter 绕过后的文档缺失。它不阻止你绕过 linter,只是要求你记录下来,并通过 CI 和代码审查来强制执行这一纪律。
对于使用 AI 编码工具的团队来说,Shamefile 尤其有价值。AI 生成的代码经常包含盲目的 linter 静音注释,而 Shamefile 迫使 AI(或使用 AI 的开发者)停下来思考:”这条警告真的可以忽略吗?”
💡 小贴士:建议在项目文档中约定
why字段的写作规范——包含具体的技术原因(”第三方库限制”)、引用相关的 issue 编号(”跟踪 ISSUE-5678″)、以及预期的修复时间线(”待 v4 重构后修复”)。这样shamefile.yaml本身就成了一份技术债追踪清单。
项目地址: github.com/BKDDFS/shamefile
安装: npm install -g shamefile / pip install shamefile / cargo install shamefile