1
0

chore: 新增 backend-code-lint 变更计划,更新 .gitignore

This commit is contained in:
2026-04-24 00:19:56 +08:00
parent 1d7e839b49
commit 4c78ab6cc8
10 changed files with 539 additions and 0 deletions

View File

@@ -0,0 +1,174 @@
# Code Lint
## Purpose
定义后端 Go 代码静态分析规则,将编码规范从人工约定升级为机器可检查的硬约束,通过 golangci-lint 在开发和提交阶段自动拦截违规代码。
## ADDED Requirements
### Requirement: golangci-lint 配置
系统 SHALL 通过 `.golangci.yml` 配置 golangci-lint启用 13 个 linter。
#### Scenario: 配置文件位置
- **WHEN** 配置 lint 规则
- **THEN** 配置文件 SHALL 位于 `backend/.golangci.yml`
#### Scenario: 启用的 linter 列表
- **WHEN** 运行 golangci-lint
- **THEN** SHALL 启用以下 linterforbidigo、errorlint、errcheck、staticcheck、revive、gocritic、gosec、bodyclose、noctx、nilerr、gofumpt、goimports、gocyclo
### Requirement: forbidigo 日志输出约束
系统 SHALL 通过 forbidigo 禁止在正式代码中使用直接输出函数。
#### Scenario: 禁止 fmt.Print 系列
- **WHEN** 正式代码中调用 fmt.Print、fmt.Println、fmt.Printf
- **THEN** lint SHALL 报错,提示使用 zap logger
#### Scenario: 禁止 fmt.Fprint 到 Stdout/Stderr
- **WHEN** 正式代码中调用 fmt.Fprintf(os.Stdout, ...) 或 fmt.Fprintf(os.Stderr, ...)
- **THEN** lint SHALL 报错,提示使用 zap logger
#### Scenario: 禁止标准库 log
- **WHEN** 正式代码中调用 log.Print、log.Fatal、log.Panic、log.Printf 等
- **THEN** lint SHALL 报错,提示使用 zap logger
#### Scenario: 禁止 zap.L() 全局 logger
- **WHEN** 正式代码中调用 zap.L()
- **THEN** lint SHALL 报错,提示通过 DI 注入 *zap.Logger
#### Scenario: 禁止 zap.S() Sugar logger
- **WHEN** 代码中调用 zap.S()
- **THEN** lint SHALL 报错,不使用 Sugar logger
#### Scenario: 允许 fmt.Sprintf 和 fmt.Errorf
- **WHEN** 代码中使用 fmt.Sprintf 或 fmt.Errorf
- **THEN** lint SHALL NOT 报错
#### Scenario: 测试代码放宽
- **WHEN** 测试文件(*_test.go或 tests/ 目录中使用 fmt.Print 系列
- **THEN** forbidigo SHALL NOT 报错
### Requirement: errorlint 错误比较约束
系统 SHALL 通过 errorlint 强制使用类型安全的错误比较方式。
#### Scenario: 禁止 err == sentinel 比较
- **WHEN** 代码中使用 `err == someError` 直接比较错误
- **THEN** lint SHALL 报错,要求使用 errors.Is()
#### Scenario: 禁止直接类型断言
- **WHEN** 代码中使用 `err.(SomeType)` 直接类型断言
- **THEN** lint SHALL 报错,要求使用 errors.As()
### Requirement: errcheck 错误返回值检查
系统 SHALL 通过 errcheck 禁止忽略函数返回的错误。
#### Scenario: 启用 check-blank
- **WHEN** 代码中使用 `_ = someFuncReturnsError()`
- **THEN** lint SHALL 报错(除非排除列表中的函数)
#### Scenario: 启用 check-type-assertions
- **WHEN** 代码中使用未检查的类型断言 `v := x.(Type)`
- **THEN** lint SHALL 报错
#### Scenario: 排除 fmt.Fprintf
- **WHEN** 代码中忽略 fmt.Fprintf 的返回值
- **THEN** errcheck SHALL NOT 报错io.Writer 场景合理)
#### Scenario: 测试代码放宽
- **WHEN** 测试文件中忽略错误返回值
- **THEN** errcheck 的 check-blank SHALL 放宽
### Requirement: revive 代码风格规则
系统 SHALL 通过 revive 启用精选的 8 条代码风格规则。
#### Scenario: 启用的规则
- **WHEN** 运行 revive
- **THEN** SHALL 启用exported、var-naming、indent-error-flow、error-strings、error-return、blank-imports、context-as-argument、unexported-return
#### Scenario: 测试代码排除 exported
- **WHEN** 测试文件中的导出符号缺少文档注释
- **THEN** revive SHALL NOT 报错
### Requirement: gosec 安全检查
系统 SHALL 通过 gosec 检查常见安全问题。
#### Scenario: 正式代码全部启用
- **WHEN** 正式代码中存在安全隐患硬编码凭证、SQL 注入等)
- **THEN** gosec SHALL 报错
#### Scenario: 测试代码排除部分规则
- **WHEN** 测试文件中触发 G101硬编码密钥、G401/G501弱密码算法
- **THEN** gosec SHALL NOT 报错
### Requirement: gocyclo 圈复杂度控制
系统 SHALL 通过 gocyclo 控制函数复杂度。
#### Scenario: 正式代码复杂度阈值
- **WHEN** 正式代码中函数圈复杂度超过 10
- **THEN** gocyclo SHALL 报错
#### Scenario: 测试代码复杂度阈值
- **WHEN** 测试代码中函数圈复杂度超过 20
- **THEN** gocyclo SHALL 报错
### Requirement: goimports import 排序
系统 SHALL 通过 goimports 统一 import 分组排序。
#### Scenario: 三组格式
- **WHEN** 格式化 import
- **THEN** SHALL 按标准库、第三方库、本地包nex/backend三组排序
- **THEN** local-prefixes SHALL 配置为 nex/backend
### Requirement: 生成代码排除
系统 SHALL 排除自动生成的代码的 lint 检查。
#### Scenario: mocks 目录排除
- **WHEN** lint 扫描 tests/mocks/ 目录
- **THEN** SHALL 排除该目录(由 mockgen 生成的代码)
#### Scenario: Code generated 标记自动检测
- **WHEN** 文件包含 `// Code generated by` 标记
- **THEN** golangci-lint SHALL 自动排除该文件
### Requirement: embedfs 编译兼容
系统 SHALL 确保 golangci-lint 能正常加载 embedfs 模块。
#### Scenario: 空目录占位
- **WHEN** embedfs 模块的 assets/ 和 frontend-dist/ 目录不存在
- **THEN** SHALL 通过 .gitkeep 文件确保目录存在
- **THEN** go:embed 指令 SHALL 能正常匹配