2026年5月28日 2 分钟阅读

Shamefile 实战指南:让每个 Linter 绕过都有据可查

tinyash 0 条评论

问题的起点:无声的技术债

在任何一个有一定规模的代码库中,你几乎都能找到这样的注释:

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 的工作方式很直接:

  1. 扫描代码库中所有的 linter 静音标记
  2. 将发现的绕过记录写入 shamefile.yaml
  3. 要求每个条目都必须填写 why 字段(为什么绕过)
  4. 在 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,你可以:

  1. 运行 shame me . 一次性发现所有绕过
  2. 逐个评估——能修复的直接修复,不能修复的记下原因
  3. 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

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。