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 [![Go 测试](https://static.pigsec.cn/wp-content/uploads/repos/cas/63/6394f52f17803c0c1e5493f4b28c512111a216ee10cb26a4c72e4ff51d379195.svg)](https://github.com/beltranaceves/uber-go-lint-style/actions/workflows/go-test.yml) [![覆盖率状态](https://codecov.io/gh/beltranaceves/uber-go-lint-style/branch/main/graph/badge.svg)](https://codecov.io/gh/beltranaceves/uber-go-lint-style) [![Go 报告卡](https://goreportcard.com/badge/github.com/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 插件。


## 目录 - [概述](#overview) - [示例运行](#samples) - [安装](#installation) - [前置条件](#prerequisites) - [设置选项 1:自动设置(推荐)](#setup-option-1-automated-setup-recommended) - [设置选项 2:手动配置](#setup-option-2-manual-configuration) - [规则](#rules) - [开发](#development) - [项目结构](#project-structure) - [添加新规则](#adding-a-new-rule) - [运行测试](#running-tests) - [贡献](#contributing) - [资源](#resources) ## 概述 这是一个自定义的 linter,旨在通过静态分析来强制执行 Uber 的内部 Go 编码标准。它旨在尽早捕获风格违规,并引导开发者编写更安全、更易于维护的代码模式。 ## 示例
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 ```
## 安装 ### 前置条件 - 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 文件用于署名。
标签:EVTX分析, Go, golangci-lint, Ruby工具, 云安全监控, 代码审查, 代码规范, 插件, 静态分析