beltranaceves/uber-go-lint-style
GitHub: beltranaceves/uber-go-lint-style
一个针对 Uber Go 风格规范的 golangci-lint 插件,用于静态检查和强制执行 Uber 内部 Go 代码标准。
Stars: 0 | Forks: 0
# uber-go-lint-style
[](https://github.com/beltranaceves/uber-go-lint-style/actions/workflows/go-test.yml)
[](https://codecov.io/gh/beltranaceves/uber-go-lint-style)
[](https://goreportcard.com/report/github.com/beltranaceves/uber-go-lint-style)
一个用于 [Uber 的 Go 风格指南](https://github.com/uber-go/guide)的 golangci-lint 插件。
## 安装
### 前置条件
- Go 1.23+
- golangci-lint 1.59.0+ ([安装文档](https://golangci-lint.run/usage/install/))
请按照以下步骤操作:
### 设置选项 1:自动设置(推荐)
运行设置脚本以自动生成配置文件:
```
go run github.com/beltranaceves/uber-go-lint-style/cmd/setup@latest
```
这将创建:
- `.custom-gcl.yml` — 插件配置
- `.golangci.yml` — Linter 设置
- `Makefile` — 构建和运行命令
然后只需:
```
make uber_lint
```
### 设置选项 2:手动配置
如果您倾向于手动设置,请按照以下步骤操作:
**步骤 1:创建 `.custom-gcl.yml`**
```
version: v2.11.4
plugins:
- module: 'github.com/beltranaceves/uber-go-lint-style'
import: 'github.com/beltranaceves/uber-go-lint-style'
version: 'latest'
```
**步骤 2:创建 `.golangci.yml` 以启用插件和规则**
```
version: "2"
linters:
default: none
enable:
- uber-go-lint-style
settings:
custom:
uber-go-lint-style:
type: "module"
description: "Uber Go style guide linter"
original-url: "github.com/beltranaceves/uber-go-lint-style"
# Disabled rules provided as YAML text. By default exclude TodoRule.
settings:
disabled_rules_yaml: |
- todo
severity:
default: info
rules:
- linters:
- uber-go-lint-style
severity: warning
```
**通过 YAML 禁用插件规则**
`uber-go-lint-style` 插件接受 `.golangci.yml` 中 `settings`
部分里的 YAML 字符串,以便在运行时禁用特定的分析器。
您可以提供一个普通的 YAML 列表,或者提供一个带有 `disabled:`(或
`disable:`)键的映射。其中的条目必须与规则通过
`BuildAnalyzer()` 返回的分析器名称相匹配。
示例(`.golangci.yml`):
```
linters:
settings:
custom:
uber-go-lint-style:
settings:
disabled_rules_yaml: |
- TodoRule
- AtomicRule
- MapInitRule
```
**步骤 3:构建自定义二进制文件并运行**
```
golangci-lint custom
./custom-gcl run --config .golangci.uber_style.yml
```
**步骤 4:添加 Makefile(可选)**
为了避免每次都手动运行命令,请将这些目标添加到您的 `Makefile` 中:
```
.PHONY: uber_lint
uber_lint: # Run Uber Go style linter (builds plugin if needed)
$Q echo "Running Uber Go style linter (with golangci-lint)..."
$Q if [ ! -f "./custom-gcl" ]; then echo "Building custom golangci-lint with uber-go-lint-style plugin..."; golangci-lint custom || exit 1; fi; echo "Running Uber Go style golangci-lint..." ;./custom-gcl run --config .golangci.uber_style.yml
.PHONY: uber_clean
uber_clean: # Clean Uber Go style linter artifacts
$Q rm -f custom-gcl*
$Q echo "Cleaned Uber Go style linter artifacts"
```
这会在首次运行时自动构建二进制文件,并在后续运行中将其缓存。然后只需:
```
make uber_lint
```
## 规则
有关完整的规则描述和示例,请参见 [RULES.md](RULES.md)。
## 开发
### 项目结构
```
uber-go-lint-style/
├── plugin.go # golangci-lint plugin entry point
├── plugin_test.go # plugin tests
├── rules/ # rule implementations (one file per rule)
├── testdata/ # testdata used by rule tests
├── cmd/ # helper CLI tools (e.g., setup)
│ └── setup/ # setup command source
├── style_guide/ # generated and source docs for the style guide
│ └── rules/ # markdown source files for the guide
├── test-client/ # integration test client and examples
├── assets/ # images and other assets
├── Makefile # convenience targets
├── installation.md # installation instructions
└── RULES.md # rule descriptions and examples
```
### 添加新规则
1. 在 `rules/` 中创建一个新文件(例如 `rules/myrule.go`):
```
package rules
import (
"golang.org/x/tools/go/analysis"
)
type MyRule struct{}
func (r *MyRule) BuildAnalyzer() *analysis.Analyzer {
return &analysis.Analyzer{
Name: "myrule",
Doc: "enforce your style convention",
Run: r.run,
}
}
func (r *MyRule) run(pass *analysis.Pass) (any, error) {
// Your linting logic here
return nil, nil
}
```
2. 在 `testdata/src/testlintdata/myrule/` 中添加测试数据:
```
package myrule_test
// Violations here
func bad() {
undesirable code // want "error message"
}
// Good practices here
func good() {
}
```
3. 在 `plugin_test.go` 中添加测试:
```
func TestMyRule(t *testing.T) {
// Similar to existing test patterns
}
```
4. 在 `plugin.go` 中注册:
```
func (f *PluginExample) BuildAnalyzers() ([]*analysis.Analyzer, error) {
return []*analysis.Analyzer{
(&rules.TodoRule{}).BuildAnalyzer(),
(&rules.AtomicRule{}).BuildAnalyzer(),
(&rules.MyRule{}).BuildAnalyzer(), // Add here
}, nil
}
```
### 运行测试
```
go test ./...
```
## 资源
- [uber-go/guide](https://github.com/uber-go/guide) — Uber 的 Go 风格指南
- [golangci-lint 插件](https://golangci-lint.run/docs/plugins/plugins-configuration/) — 自定义插件文档
- 分析工具:
- [go/analysis](https://pkg.go.dev/golang.org/x/tools/go/analysis)
- [golang.org/x/tools/go/ssa](https://pkg.go.dev/golang.org/x/tools/go/ssa)
- [go/ast](https://pkg.go.dev/go/ast)
- [go/types](https://pkg.go.dev/go/types)
## 许可证
本项目基于 Apache License, Version 2.0 授权。有关详细信息,请参见
[LICENSE](LICENSE) 文件。在适用的情况下,包含了一份 NOTICE
文件用于署名。
Cadence - 19/05/2026
``` echo "Running Uber Go style linter (with golangci-lint)..." Running Uber Go style linter (with golangci-lint)... if [ ! -f "./custom-gcl" ]; then echo "Building custom golangci-lint with uber-go-lint-style plugin..."; golangci-lint custom || exit 1; fi; echo "Running Uber Go style golangci-lint..." ;./custom-gcl run --config .golangci.yml Running Uber Go style golangci-lint... common/clock/event_timer_gate.go:45:3: struct_embed: embedded field should be placed at the top of the struct (uber-go-lint-style) sync.RWMutex ^ common/clock/event_timer_gate.go:57:25: struct_field_key: use field names when initializing structs; specify fields like `Field: value` (uber-go-lint-style) fireTime: time.Time{}, ^ common/clock/event_timer_gate.go:79:2: var_scope: identifier 'active' can be declared in the inner block to reduce its scope (uber-go-lint-style) active := t.currentTime.Before(t.fireTime) ^ common/clock/event_timer_gate.go:113:24: struct_field_key: use field names when initializing structs; specify fields like `Field: value` (uber-go-lint-style) t.fireTime = time.Time{} ^ common/clock/event_timer_gate_test.go:44:7: struct_pointer: use &T instead of new T when initializing struct references (uber-go-lint-style) s := new(eventTimerGateSuite) ^ common/clock/ratelimiter.go:186:35: struct_field_key: use field names when initializing structs; specify fields like `Field: value` (uber-go-lint-style) _ Reservation = deniedReservation{} ^ common/clock/ratelimiter.go:228:2: var_scope: identifier 'newNow' can be declared in the inner block to reduce its scope (uber-go-lint-style) newNow := r.timesource.Now() // caution: must be after acquiring the lock ^ common/clock/ratelimiter.go:280:2: var_scope: identifier 'res' can be declared in the inner block to reduce its scope (uber-go-lint-style) res := r.limiter.ReserveN(now, 1) ^ common/clock/ratelimiter.go:358:5: var_scope: identifier 'err' can be declared in the inner block to reduce its scope (uber-go-lint-style) if err := ctx.Err(); err != nil { ^ common/clock/ratelimiter.go:378:2: var_scope: identifier 'delay' can be declared in the inner block to reduce its scope (uber-go-lint-style) delay := res.DelayFrom(now) ^ common/clock/ratelimiter.go:463:2: var_scope: identifier 'called' can be declared in the inner block to reduce its scope (uber-go-lint-style) called := false ^ common/clock/ratelimiter_bench_test.go:97:2: decl_group: group adjacent var declarations into a single var block (uber-go-lint-style) var runSerial runType = func(b *testing.B, each func(int) bool) { ^ common/clock/ratelimiter_bench_test.go:100:7: var_scope: identifier 'i' can be declared in the inner block to reduce its scope (uber-go-lint-style) for i := 0; i < b.N; i++ { ^ common/clock/ratelimiter_bench_test.go:109:3: var_scope: identifier 'allowedPeriod' can be declared in the inner block to reduce its scope (uber-go-lint-style) allowedPeriod := fmt.Sprintf(allowedPeriodFmt, "n/a") ^ common/clock/ratelimiter_bench_test.go:118:16: var_scope: identifier 'denied' can be declared in the inner block to reduce its scope (uber-go-lint-style) var allowed, denied atomic.Int64 ^ common/clock/ratelimiter_bench_test.go:120:4: var_scope: identifier 'n' can be declared in the inner block to reduce its scope (uber-go-lint-style) n := 0 ^ common/clock/ratelimiter_bench_test.go:132:3: var_scope: identifier 'allowedPeriod' can be declared in the inner block to reduce its scope (uber-go-lint-style) allowedPeriod := fmt.Sprintf(allowedPeriodFmt, "n/a") ^ common/clock/ratelimiter_bench_test.go:151:6: var_scope: identifier 'rl' can be declared in the inner block to reduce its scope (uber-go-lint-style) rl := rate.NewLimiter(rate.Every(normalLimit), burst) ^ common/clock/ratelimiter_bench_test.go:157:6: var_scope: identifier 'rl' can be declared in the inner block to reduce its scope (uber-go-lint-style) rl := NewRatelimiter(rate.Every(normalLimit), burst) ^ common/clock/ratelimiter_bench_test.go:163:6: var_scope: identifier 'ts' can be declared in the inner block to reduce its scope (uber-go-lint-style) ts := NewMockedTimeSource() ^ common/clock/ratelimiter_bench_test.go:206:7: var_scope: identifier 'r' can be declared in the inner block to reduce its scope (uber-go-lint-style) r := rl.Reserve() ^ common/clock/ratelimiter_bench_test.go:229:7: var_scope: identifier 'r' can be declared in the inner block to reduce its scope (uber-go-lint-style) r := rl.ReserveN(now, 1) ^ common/clock/ratelimiter_bench_test.go:262:6: var_scope: identifier 'ts' can be declared in the inner block to reduce its scope (uber-go-lint-style) ts := NewMockedTimeSource() ^ common/clock/ratelimiter_bench_test.go:318:8: var_scope: identifier 'rl' can be declared in the inner block to reduce its scope (uber-go-lint-style) rl := NewRatelimiter(limit, burst) ^ common/clock/ratelimiter_comparison_test.go:86:7: var_scope: identifier 'testnum' can be declared in the inner block to reduce its scope (uber-go-lint-style) for testnum := 0; !t.Failed() && time.Now().Before(deadline); testnum++ { ^ common/clock/ratelimiter_comparison_test.go:120:5: var_scope: identifier 'seed' can be declared in the inner block to reduce its scope (uber-go-lint-style) seed := time.Now().UnixNano() ^ common/clock/ratelimiter_comparison_test.go:256:3: var_scope: identifier 'round' can be declared in the inner block to reduce its scope (uber-go-lint-style) round := make([]string, events) ^ common/clock/ratelimiter_comparison_test.go:269:3: var_scope: identifier 'set' can be declared in the inner block to reduce its scope (uber-go-lint-style) set := rng.Intn(len(schedule) + 1) ^ common/clock/ratelimiter_comparison_test.go:320:2: var_scope: identifier 'compressed' can be declared in the inner block to reduce its scope (uber-go-lint-style) compressed := NewRateLimiterWithTimeSource(compressedTS, limit, burst) ^ common/clock/ratelimiter_comparison_test.go:325:2: var_scope: identifier 'compressedReplay' can be declared in the inner block to reduce its scope (uber-go-lint-style) compressedReplay := make([][]func(t *testing.T), rounds) ^ common/clock/ratelimiter_comparison_test.go:456:6: var_scope: identifier 'done' can be declared in the inner block to reduce its scope (uber-go-lint-style) done := make(chan struct{}) ^ common/clock/ratelimiter_comparison_test.go:547:2: var_scope: identifier 'maxLatency' can be declared in the inner block to reduce its scope (uber-go-lint-style) maxLatency := maxDur(actual, wrapped, mocked) ^ common/clock/ratelimiter_comparison_test.go:548:2: var_scope: identifier 'minLatency' can be declared in the inner block to reduce its scope (uber-go-lint-style) minLatency := minDur(actual, wrapped, mocked) ^ common/clock/ratelimiter_comparison_test.go:573:3: var_scope: identifier 'assertNoWait' can be declared in the inner block to reduce its scope (uber-go-lint-style) assertNoWait := func(what string, wait time.Duration) { ^ common/clock/ratelimiter_comparison_test.go:585:3: var_scope: identifier 'assertWaited' can be declared in the inner block to reduce its scope (uber-go-lint-style) assertWaited := func(what string, wait time.Duration) { ^ common/clock/ratelimiter_test.go:42:3: var_scope: identifier 'name' can be declared in the inner block to reduce its scope (uber-go-lint-style) name := name ^ common/clock/ratelimiter_test.go:45:4: var_scope: identifier 'ts' can be declared in the inner block to reduce its scope (uber-go-lint-style) ts := func() MockedTimeSource { return nil } ^ common/clock/ratelimiter_test.go:293:5: struct_field_zero: omit zero-valued field "drainFirst" from struct literal; let Go set the zero value (uber-go-lint-style) drainFirst: false, ^ common/clock/ratelimiter_test.go:306:5: struct_field_zero: omit zero-valued field "allowed" from struct literal; let Go set the zero value (uber-go-lint-style) allowed: 0, ^ common/clock/ratelimiter_test.go:353:5: struct_field_zero: omit zero-valued field "drainFirst" from struct literal; let Go set the zero value (uber-go-lint-style) drainFirst: false, ^ common/clock/ratelimiter_test.go:399:5: struct_field_zero: omit zero-valued field "allowed" from struct literal; let Go set the zero value (uber-go-lint-style) allowed: 0, ^ common/clock/ratelimiter_test.go:447:11: type_assert: use the comma-ok form for type assertions (uber-go-lint-style) impl := rl.(*ratelimiter) ^ common/clock/ratelimiter_test.go:451:12: type_assert: use the comma-ok form for type assertions (uber-go-lint-style) rimpl := r.(*allowedReservation) ^ common/clock/sustain.go:25:1: decl_group: group import declarations into a single import block (uber-go-lint-style) import "time" ^ common/clock/sustain.go:48:3: var_scope: identifier 'now' can be declared in the inner block to reduce its scope (uber-go-lint-style) now := s.source.Now() ^ common/clock/sustain.go:68:3: var_scope: identifier 'now' can be declared in the inner block to reduce its scope (uber-go-lint-style) now := s.source.Now() ^ common/clock/sustain_test.go:111:4: struct_field_zero: omit zero-valued field "duration" from struct literal; let Go set the zero value (uber-go-lint-style) duration: 0, ^ common/clock/sustain_test.go:210:4: struct_field_zero: omit zero-valued field "duration" from struct literal; let Go set the zero value (uber-go-lint-style) duration: 0, ^ common/clock/timer_gate.go:47:3: struct_embed: add an empty line between embedded fields and regular fields (uber-go-lint-style) timeSource TimeSource ^ common/clock/timer_gate_test.go:43:7: struct_pointer: use &T instead of new T when initializing struct references (uber-go-lint-style) s := new(timerGateSuite) ^ 50 issues: * uber-go-lint-style: 50 make: *** [Makefile:6: uber_lint] Error 1 ```标签:EVTX分析, Go, golangci-lint, Ruby工具, 云安全监控, 代码审查, 代码规范, 插件, 静态分析