- 开发工具
- 代码质量
- 静态分析
- CLI
【免费下载链接】revive
🔥 Fast, strict, configurable, extensible, and beautiful linter for Go
导读:revive 是一个快速、可配置、可扩展的 Go 静态分析工具(linter),而
AGENTS.md正是为 Claude Code、Copilot、Cursor、Codex 等 AI 编码代理编写的仓库内协作手册。本文以该文档为核心骨架,结合仓库源码(lint/、rule/、config/、formatter/等)逐节展开,带你掌握 revive 的顶层架构、构建测试链路、规则与 formatter 的开发规范,以及 AI 代理在本仓库工作时必须遵守的硬性约束——无论你是人类贡献者还是接入 AI 代理的开发者,这份指南都能帮你快速对齐仓库的编码预期,避免在 CI 与代码审查中踩坑。
1. 项目定位:revive 是什么
revive是一个快速、可配置、可扩展的 Go 语言 linter。它的核心工作方式是:
- 通过
go/ast解析 Go 源码(需要类型信息的规则则借助go/types); - 运行一组可配置的规则;
- 通过可插拔的 formatter 输出检查结果(findings)。
整个数据流从源码解析到结果输出全部解耦,这也是 revive 能够支持 100+ 规则、9 种输出格式(见 formatter/ 与 config/config.go 中注册的allFormatters)的根本原因。
1.1 顶层包结构
AGENTS.md为 AI 代理划定了清晰的顶层包地图,这是理解整个仓库的第一步:
| 包 | 职责 |
|---|---|
| cli/ | 命令行入口,main.go委托给cli.RunRevive(见 cli/main.go) |
| lint/ | 核心 lint 引擎:规则接口(Rule、ConfigurableRule)、File、Failure、Severity以及内存中的Config类型 |
| rule/ | 每条规则一个文件(100+ 条规则);无类型信息需求的规则还登记在 untyped.toml |
| formatter/ | 输出格式化器:default、json、sarif、stylish、friendly 等 |
| config/ | 配置文件(TOML)加载、默认值,以及可用规则与 formatter 的注册表 |
| revivelib/ | 将 revive 作为库嵌入的编程式 API |
| test/ | 规则测试,每条规则对应一个_test.go |
| testdata/ | 供规则测试消费的 Go 源码夹具(fixtures) |
| internal/ | 非公共 API 的内部辅助包 |
值得注意的是,revive刻意保持很小的依赖树(go.mod 中仅有BurntSushi/toml、fatih/color、golang.org/x/tools等少量直接依赖),这既是性能考量,也是仓库对依赖引入设限的原因(详见第 8 节“红线”)。
1.2 规则与格式化器两大扩展点
从架构上看,revive 的扩展完全围绕两个接口展开:
- 规则:实现 lint/rule.go 中的
lint.Rule(必须)与lint.ConfigurableRule(可选); - 格式化器:实现 lint/formatter.go 中的
lint.Formatter。
后文第 4、5 节将分别给出二者的完整开发流程。
2. 编码规范:动手写代码前先读这两份文件
AGENTS.md强调,AI 代理在写 Go 代码之前,必须先读.github/instructions/go.instructions.md——它是命名、错误处理、并发、测试风格以及现代 Go(1.21+)惯用法的唯一事实来源(single source of truth),AGENTS.md明确要求不得与其重复或矛盾。
在该文件之外,还有两条重要的补充约定:
2.1 跟随 go.mod 声明的 Go 版本
项目以 go.mod 中的go指令为准(当前为go 1.26.0)。代理应优先使用该版本下的标准库能力,而不是手写等价实现:
min/max内建函数、slices、maps、cmp.Or、errors.Join、range-over-int、slog结构化日志等;- 若建议的代码需要比 go.mod 允许的更新特性,必须明确指出,而非静默使用(见 go.instructions.md 的 Go Version Awareness 章节)。
2.2 revive 自举:项目会自己检查自己
revive 的代码库本身由 revive 与 golangci-lint 双重把关。所有代码必须同时通过:
revive --config revive.toml ./... golangci-lint run其中 revive.toml 是 revive 用于检查自身代码库的严格配置(例如将line-length-limit设为 200、filename-format禁止大写与连字符命名的.go文件等),.golangci.yml 则是 golangci-lint 的严格配置。这意味着任何新增代码都必须能通过这两套检查,否则 CI 不会放行。
3. 构建、测试与 lint:一切走 Makefile
AGENTS.md规定所有工作流都通过 Makefile 进行,这是代理在本仓库最需要记住的操作入口:
| 目标 | 作用 |
|---|---|
make build | 用版本 ldflags 构建./revive二进制 |
make test | 运行go test -v -race ./... |
make lint | 依次运行revive --config revive.toml ./...与golangci-lint run |
make fmt | 执行golangci-lint fmt格式化 |
make tidy | 执行go mod tidy -diff(有漂移即失败) |
make all | test + lint + build全量检查 |
3.1 版本信息注入(build 细节)
从 Makefile 可以看到,make build会通过-ldflags把GIT_COMMIT、GIT_VERSION、构建时间与builtBy注入cli/包中的version、commit、date、builtBy变量,并先执行tidy以保证依赖一致。这些信息最终由 cli/main.go 的getVersion函数在-version标志下输出。
3.2 运行单个规则的测试
当只改动一条规则时,无需跑全量测试:
go test -run TestUnusedParam ./test/...以argument-limit规则为例,其测试函数分别为TestArgumentsLimitDefault(无参默认值)与TestArgumentsLimit(传入参数3),并附带一个基准测试BenchmarkArgumentsLimit(见 test/argument_limit_test.go)。
3.3 本地运行时的日志
本地调试时可通过环境变量REVIVE_LOG_LEVEL控制日志级别(debug|info|warn|error),日志输出到stderr:
REVIVE_LOG_LEVEL=debug go run main.go从 logging/logger.go 的实现可以看到:REVIVE_LOG_LEVEL未设置或为空时日志被完全禁用(slog.DiscardHandler);设为非法值时回退到WARN级别;日志通过slog.NewTextHandler写到os.Stderr。更详细的说明见 DEVELOPING.md §Logging。
4. 规则开发全流程(本仓库最核心的贡献路径)
AGENTS.md把规则开发列为 AI 代理最重要的任务之一,其规范化的参考示例是:
- 规则实现:rule/argument_limit.go
- 规则测试:test/argument_limit_test.go
而完整的逐项检查清单(标识符、文件与类型命名、接口、failures、typed vs untyped、注册、测试与文档)则位于 .github/instructions/rule.instructions.md,它是规则开发的唯一事实来源,GitHub Copilot 在审查 PR 时也会应用这份清单。
4.1 必须实现的两个接口
从 lint/rule.go 可以看到:
type Rule interface { Name() string Apply(*File, Arguments) []Failure } type ConfigurableRule interface { Configure(Arguments) error }所有规则必须实现lint.Rule;带配置参数的规则还需实现lint.ConfigurableRule。Arguments是[]any的别名(见 lint/config.go),配置参数来自配置文件。
4.2 规范示例:argument-limit 规则剖析
rule/argument_limit.go 展示了完整的三段式结构:
type ArgumentsLimitRule struct { max int } const defaultArgumentsLimit = 8 var _ lint.ConfigurableRule = (*ArgumentsLimitRule)(nil)- 默认值常量:
defaultArgumentsLimit = 8,在Configure中当参数缺失时应用; - 编译期断言:
var _ lint.ConfigurableRule = (*ArgumentsLimitRule)(nil),确保接口签名写错时在构建期报错,而不是静默使规则无法配置; Configure校验参数并返回 error:argument-limit期望第一个参数是int64,非法值会返回invalid value passed as argument number to the "argument-limit" rule错误(而非 panic);Apply遍历 AST:通过file.AST.Decls遍历所有*ast.FuncDecl,统计形参数量(Params.List中每个l.Names的长度累加),超过r.max时产出lint.Failure;Name()返回 kebab-case 标识符:"argument-limit"。
Apply返回的Failure中还设置了Confidence: 1与Category: lint.FailureCategoryMaintenance(见 rule/argument_limit.go)。
4.3 命名三件套:标识符 / 文件名 / 结构体
新规则的命名必须在三处保持一致:
| 维度 | 规则 | 示例(argument-limit) |
|---|---|---|
标识符(Name()返回值) | kebab-case | argument-limit |
| 实现文件名 | snake_case,rule/<name>.go | rule/argument_limit.go |
| 结构体名 | PascalCase+Rule后缀 | ArgumentsLimitRule |
仓库中存在少量历史例外(如flag_param.go→flag-parameter、unused_param.go→unused-parameter、var_declarations.go→var-declaration,以及FunctionLength、NestedStructs等无Rule后缀的结构体),这些遗留命名保持不变,不要在无关修复中强求改名。
4.4 Configure 的幂等性:单例规则的必修课
这是 AI 代理最容易写错、却最影响正确性的细节。allRules中的规则都是单例(见 config/config.go 的GetLintingRules),同一个实例可能被Configure多次调用——因此:
Configure必须在读取参数之前把所有可配置字段重置为默认值;- 即使参数为空提前返回,也不能跳过重置(否则上一次调用残留的状态会污染后续调用);
- 仅当 map 参数中存在某 key 时才赋值,效果等同于保留旧值,同样会出问题。
规范写法如下(摘自 rule.instructions.md):
func (r *SomeRule) Configure(arguments lint.Arguments) error { r.max = defaultMax // 在读取参数前重置所有字段 r.ignore = nil // 包括 map、slice 等复合字段 r.allow = nil if len(arguments) < 1 { return nil // 提前返回也必须先完成上面的重置 } // ... }此外,Apply在多个文件间是并发执行的,因此它绝不能修改规则状态——状态只在Configure中设置。这是 revive 高性能并行的前提。
4.5 注册与启用:三步接入 CLI
- 加入
allRules:在 config/config.go 的allRules切片中追加规则实例,CLI 才能发现它; - 更新
allRulesCount:config/config_test.go 中的计数需要同步增加,否则 enable-all 相关测试会失败; - 在配置文件中启用:在 revive.toml(仓库自检)或用户的 TOML 配置中加入对应段落。
规则的启用解析由config.EnabledRules与GetLintingRules完成:后者会把config.Rules中Disabled=false的规则取出,若规则实现了ConfigurableRule则调用其Configure,任何配置错误都会以cannot configure rule形式直接返回错误(见 config/config.go)。另外actualRuleName还兼容了imports-blacklist与imports-blocklist的旧名映射。
4.6 Typed 与 untyped:别破坏无类型快路径
revive 区分两种规则:
- typed 规则:使用
file.Pkg.TypeCheck()或任何go/types能力; - untyped 规则:纯 AST/语法层面工作,不触碰类型信息。
新增untyped规则时,必须把规则名加入 untyped.toml(保持文件有序);typed 规则绝不能列入其中。AGENTS.md特别警告:在把规则加入 untyped.toml 之前,必须验证它确实不依赖类型信息——搞错会静默破坏 untyped 快速路径(fast path),导致全仓库检查性能回退。
4.7 Failure 的 Confidence 与 Category 约定
每条lint.Failure必须满足(见 rule.instructions.md 的 Failures 章节):
- 设置
Category为 lint/failure.go 中lint.FailureCategory*常量之一,测试脚手架对空 Category 会直接判失败; Confidence反映检测的确定程度:只有确定不是误报时才用1;依赖启发式的规则应使用更低的值(如0.8)。默认置信度阈值是0.8(config.DefaultConfidence),低于阈值的 failure 在用户不调低阈值时不会展示;测试脚手架以阈值0运行,无法暴露这一点。因此只有确实需要时才低于0.8;- 失败消息应简洁、可执行。
4.8 测试:标准库 + 共享 harness
规则测试位于 test/<rule_name>_test.go(一条规则一个文件),使用共享的testRuleharness 与标准库testing包——禁止引入断言库(testify、gomega 等)。夹具(fixtures)放在 testdata/ 下,需覆盖触发与不触发两种情形以及规则暴露的每个配置选项;可配置规则还要求一个Configure重置测试(复用同一实例,先带全部选项跑一遍,再在无参数默认值下跑一遍应通过的夹具,参见 test/file_length_limit_test.go)。
4.9 规则文档双件套
新规则还需同步两份用户文档:
- README.md:在规则表格中新增一行,正确填写
Config、Go version、golint、Typed列; - RULES_DESCRIPTIONS.md:新增
## <rule-name>章节(含_Go version_、_Description_、_Configuration_,可配置规则附 TOML 示例),以及### Examples (<rule-name>)触发/不触发示例代码块。
新增行与章节需按字母序就近排列;目录(TOC)由markdown-toc生成,禁止手改(详见第 6 节)。
5. 新增 formatter:实现、注册、写文档
formatter 是 revive 的另一扩展点,开发步骤为:
5.1 实现lint.Formatter接口
formatter/ 下已有 checkstyle、default、json、ndjson、plain、sarif、stylish、unix 等实现。接口定义在 lint/formatter.go:
Format(<-chan lint.Failure, lint.Config) (string, error) Name() stringFormat接收一个lint.Failure通道与lint.Config,返回格式化后的输出字符串与错误;Name()返回 formatter 的标识名。
5.2 三步注册
- 把实现放在
formatter/<name>.go; - 追加到 config/config.go 的
allFormatters切片(保持有序并与 README 同步),这样config.GetFormatter才能找到它; - 在 README.md 的 formatter 表格中新增一行。
6. Markdown 变更规范:三个工具在把关
AGENTS.md对 Markdown 文件(尤其 README.md 与 RULES_DESCRIPTIONS.md)有严格约束:
- 它们由
markdownlint-cli2做 lint 检查; - 拥有由
markdown-toc生成的目录(TOC); - 代码片段由
mdsf格式化。
因此,如果你编辑这些文件,必须运行 DEVELOPING.md §Lint Markdown files 中列出的三个工具——CI 会拒绝手写的 TOC 与未格式化的代码片段。
代码块的标记约定:
- Go 代码使用
```go; - 只有刻意不可编译的片段才使用
```golang。
行宽限制:本文档及其他 Markdown 文件的行长上限为150 字符(代码块内 200 字符),需要相应换行。
7. 提交与 PR 规范
- 提交风格:匹配现有
git log风格——conventional commits 前缀,如feature:、fix:、fix(deps):、chore(deps):,通常后跟#<PR>引用; - PR 聚焦与原子化:保持 PR 小且聚焦;非平凡的改动先开 issue 讨论(见 CONTRIBUTING.md);
- PR 模板:位于 .github/PULL_REQUEST_TEMPLATE.md,需填写动机、测试覆盖并链接来源 issue;
- 本地验证:push 前运行
make all;CI 会运行同样的检查,外加 Markdown lint、TOC 检查与mdsf verify。
另外,AGENTS.md还提及贡献前先为仓库加星(star)以示支持——这是一个社区约定,不影响技术流程。
8. Agent 红线:这些事绝对不能做
AGENTS.md第 8 节列出了 AI 代理在本仓库工作时的高压线,违反任何一条都会被审查者否决:
- 禁止用
//nolint或// revive:disable压制检查结果来让 CI 变绿——应当修复底层代码;压制需要理由注释与审查者批准; - 禁止放宽 .golangci.yml 或 revive.toml 中的阈值来绕过检查结果;
- 禁止无充分理由添加依赖——revive 刻意保持很小的依赖树,添加后要运行
go mod tidy; - 禁止引入断言库(testify、gomega 等)——项目按设计使用标准库
testing包; - 禁止重构或重排与本次改动无关的文件——保持 diff 可审查;
- 禁止手改 README.md / RULES_DESCRIPTIONS.md 中生成的 TOC;
- 禁止让
Configure保留上一次调用的状态——规则是单例,可能被多次配置,必须先在读取参数前把每个可配置字段重置为默认值(包括空参数提前返回的分支); - 禁止把规则加入 untyped.toml,除非已确认它确实不触碰类型信息——否则会静默破坏 untyped 快速路径。
前两条的本质一致:不要让检查工具“看不见”问题,而要真正把问题修好。这既是代码质量要求,也是 revive 对自身“被自己检查”这一自举文化的坚持。
9. 疑难速查表:卡住时去哪里找答案
AGENTS.md末尾为代理提供了一张速查表,按“需要什么 → 去哪里找”组织。结合本文的源码印证,整理如下:
| 需要什么 | 文件 / 目录 |
|---|---|
| Go 风格与惯用法 | .github/instructions/go.instructions.md |
| 规则开发检查清单(PR 审查用) | .github/instructions/rule.instructions.md |
| 构建 / 测试 / lint 命令 | Makefile、DEVELOPING.md |
| 规则开发的工作示例 | rule/argument_limit.go + test/argument_limit_test.go |
规则接口、File、Failure | lint/ |
| 默认配置包 | defaults.toml、revive.toml |
| 面向用户的规则文档 | RULES_DESCRIPTIONS.md |
| CLI 标志与行为 | cli/ |
| 编程式嵌入 | revivelib/ |
9.1 快速自检清单(提交前过一遍)
综合AGENTS.md与两份 instructions 文件,一个合格的规则/修复提交应满足:
- 通过
make all(test + lint + build),且go mod tidy -diff无漂移; - 新规则:命名三件套一致、实现
lint.Rule(必要时ConfigurableRule并带编译期断言)、Configure重置状态、注册进allRules、同步allRulesCount、untyped 规则列入 untyped.toml、补齐test/与testdata/、更新 README 表格与 RULES_DESCRIPTIONS 章节; - 没有使用
//nolint或// revive:disable规避检查; - 没有引入新依赖或断言库;
- diff 保持聚焦,未动无关文件。
结语:一份给 AI 代理的“仓库宪法”
AGENTS.md的价值不在于罗列命令,而在于把 revive 仓库数十个贡献者形成的协作惯例浓缩成一份可供 AI 代理与人类共同遵守的“仓库宪法”:架构地图(第 1 节)、编码标准(第 2 节)、工具链入口(第 3 节)、规则与 formatter 的扩展范式(第 4、5 节)、文档约束(第 6 节)、提交规范(第 7 节)、不可触碰的红线(第 8 节)与速查索引(第 9 节)。当 AI 代理(或开发者)在rule/中新增一条规则、在formatter/中新增一种输出、或仅仅是修复一个 lint finding 时,遵循这份文档就能与仓库的 CI、代码审查流程无缝对齐——这正是 revive 能把“快速、严格、可配置、可扩展”四个特性同时落地的组织保障。
- 开发工具
- 代码质量
- 静态分析
- CLI
【免费下载链接】revive
🔥 Fast, strict, configurable, extensible, and beautiful linter for Go
相关推荐
Gradio 仓库 AI 编码代理协作指南:从仓库结构到 Pull Request 流程的完整规范
Gradio 仓库 AI 编码代理协作指南:从仓库结构到 Pull Request 流程的完整规范 本指南以 Gradio 开源仓库根目录的 AGENTS.md
前端后端AI 应用Cosmos SDK 编码代理贡献指南:仓库架构、开发工作流与 AI Agent 协作规范
Cosmos SDK 编码代理贡献指南:仓库架构、开发工作流与 AI Agent 协作规范 本文是 Cosmos SDK 仓库中 AGENTS.md https
区块链Rollup 仓库 Agent 协作开发指南:从代码规范、双端架构到构建与测试工作流
Rollup 仓库 Agent 协作开发指南:从代码规范、双端架构到构建与测试工作流 Rollup 是一个用 TypeScript 与 Rust 混合实现的下一
前端构建构建工具开发工具CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考