Skip to content

Commit 5f353a0

Browse files
pieternclaude
andauthored
Add lint rule for context.Background() in non-test code (#4664)
## Summary - Add a gorules lint rule that flags `context.Background()` usage in all files except `main.go`, suggesting `t.Context()` in tests or passing context from the caller - Add context guidelines to AGENTS.md Builds on #4655, #4656, and #4657. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a530f2d commit 5f353a0

File tree

8 files changed

+18
-13
lines changed

8 files changed

+18
-13
lines changed

AGENTS.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ Use table-driven tests when testing multiple similar cases (e.g., different inpu
188188

189189
**Template tests**: Tests in `acceptance/bundle/templates` include materialized templates in output directories. These directories follow the same `out` convention — everything starting with `out` is generated output. Sources are in `libs/template/templates/`. Use `make test-update-templates` to regenerate. If linters or formatters find issues in materialized templates, do not fix the output files — fix the source in `libs/template/templates/`, then regenerate.
190190

191+
# Context
192+
193+
Always pass `context.Context` as a function argument; never store it in a struct. Storing context in a struct obscures the lifecycle and prevents callers from setting per-call deadlines, cancellation, and metadata (see https://go.dev/blog/context-and-structs). Do not use `context.Background()` outside of `main.go` files. In tests, use `t.Context()` (or `b.Context()` for benchmarks).
194+
191195
# Logging
192196

193197
Use the following for logging:
@@ -202,7 +206,7 @@ log.Errorf(ctx, "...")
202206
```
203207

204208
Note that the 'ctx' variable here is something that should be passed in as
205-
an argument by the caller. In tests, use `t.Context()` (or `b.Context()` for benchmarks) instead of `context.Background()`. This is enforced by a lint rule.
209+
an argument by the caller.
206210

207211
Use cmdio.LogString to print to stdout:
208212

cmd/labs/project/entrypoint.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ func (e *Entrypoint) getLoginConfig(cmd *cobra.Command) (*loginConfig, *config.C
185185
if err != nil {
186186
return nil, nil, err
187187
}
188-
if isNoLoginConfig && !e.IsBundleAware && e.isAuthConfigured(defaultConfig) {
188+
if isNoLoginConfig && !e.IsBundleAware && e.isAuthConfigured(ctx, defaultConfig) {
189189
log.Debugf(ctx, "Login is configured via environment variables")
190190
return &loginConfig{}, defaultConfig, nil
191191
}
@@ -291,8 +291,8 @@ func (e *Entrypoint) environmentFromConfig(cfg *config.Config) map[string]string
291291
return env
292292
}
293293

294-
func (e *Entrypoint) isAuthConfigured(cfg *config.Config) bool {
294+
func (e *Entrypoint) isAuthConfigured(ctx context.Context, cfg *config.Config) bool {
295295
r := &http.Request{Header: http.Header{}}
296-
err := cfg.Authenticate(r.WithContext(context.Background()))
296+
err := cfg.Authenticate(r.WithContext(ctx))
297297
return err == nil
298298
}

cmd/labs/project/login.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func (lc *loginConfig) askWorkspaceProfile(ctx context.Context, cfg *config.Conf
5353
// Check if authentication is already configured (e.g., via environment variables).
5454
// This is consistent with askCluster() and askWarehouse() which check if their
5555
// values are already set before prompting.
56-
if lc.isAuthConfigured(cfg) {
56+
if lc.isAuthConfigured(ctx, cfg) {
5757
return err
5858
}
5959
if !cmdio.IsPromptSupported(ctx) {

experimental/aitools/cmd/query.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ func executeAndPoll(ctx context.Context, api sql.StatementExecutionInterface, wa
204204
// cancelStatement performs best-effort server-side cancellation.
205205
// Called on any poll exit due to context cancellation (signal or parent).
206206
cancelStatement := func() {
207-
cancelCtx, cancel := context.WithTimeout(context.Background(), cancelTimeout)
207+
// Use the parent context (ctx), not the cancelled pollCtx.
208+
cancelCtx, cancel := context.WithTimeout(ctx, cancelTimeout)
208209
defer cancel()
209210
if err := api.CancelExecution(cancelCtx, sql.CancelExecutionRequest{
210211
StatementId: statementID,

experimental/aitools/lib/server/doc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ It uses the official MCP Go SDK and supports stdio transport.
66
77
Usage:
88
9-
ctx := context.Background()
9+
ctx := context.TODO()
1010
cfg := &config.Config{
1111
WarehouseID: "abc123",
1212
}

internal/testarchive/utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func logf(format string, args ...any) {
2929
// getCacheDir returns the cache directory for downloads.
3030
// It uses ~/.cache/testarchive by default.
3131
func getCacheDir() (string, error) {
32-
homeDir, err := env.UserHomeDir(context.Background())
32+
homeDir, err := env.UserHomeDir(context.Background()) //nolint:gocritic // Test utility without caller context.
3333
if err != nil {
3434
return "", fmt.Errorf("failed to get home directory: %w", err)
3535
}

libs/databrickscfg/loader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (l profileFromHostLoader) Configure(cfg *config.Config) error {
7575
return nil
7676
}
7777

78-
ctx := context.Background()
78+
ctx := context.Background() //nolint:gocritic // SDK interface does not accept context.
7979
configFile, err := config.LoadFile(cfg.ConfigFile)
8080
if err != nil {
8181
if errors.Is(err, fs.ErrNotExist) {

libs/gorules/rule_context_background.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package gorules
22

33
import "github.com/quasilyte/go-ruleguard/dsl"
44

5-
// UseTestContext detects context.Background() in test files and suggests using t.Context().
6-
func UseTestContext(m dsl.Matcher) {
5+
// NoContextBackground detects context.Background() outside of main.go files.
6+
func NoContextBackground(m dsl.Matcher) {
77
m.Match(`context.Background()`).
8-
Where(m.File().Name.Matches(`_test\.go$`)).
9-
Report(`Use t.Context() or b.Context() in tests instead of context.Background()`)
8+
Where(!m.File().Name.Matches(`^main\.go$`)).
9+
Report(`Do not use context.Background(); use t.Context() in tests or pass context from caller`)
1010
}

0 commit comments

Comments
 (0)