Skip to content

Commit bdeba80

Browse files
pieternclaude
andauthored
Add forbidigo linter rule for os.Getenv (#4700)
## Summary - Add a `forbidigo` lint rule rejecting `os.Getenv` in favor of `env.Get(ctx)` from `libs/env`, which supports context-based environment variable overrides for test isolation. - Convert all callsites where `ctx` is available. - Plumb `ctx` through `libs/completion` (`DetectShell`, `Status`, `Install`, `homebrewCompletionPath`) and `experimental/aitools/lib/installer` (`getSkillsRef`) where it was one hop away from callers that already had it. - Add `//nolint:forbidigo` with reasons where conversion is not possible (import cycles, no ctx available, process env mutation). - Exclude `_test.go` files from the rule via a golangci-lint exclusion. ## Test plan - [x] `make lintfull` passes with 0 issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 83eacdd commit bdeba80

File tree

28 files changed

+90
-75
lines changed

28 files changed

+90
-75
lines changed

.golangci.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ linters:
4444
msg: Use cmdio.IsPromptSupported(ctx) to check for a TTY.
4545
- pattern: 'os\.UserHomeDir'
4646
msg: Use env.UserHomeDir(ctx) from libs/env instead.
47+
- pattern: 'os\.Getenv'
48+
msg: Use env.Get(ctx) from the libs/env package instead of os.Getenv.
4749
analyze-types: true
4850
copyloopvar:
4951
check-alias: true
@@ -121,6 +123,10 @@ linters:
121123
- path: bundle/direct/dresources/.*_test.go
122124
linters:
123125
- exhaustruct
126+
- text: "Use env\\.Get"
127+
path: "_test\\.go$"
128+
linters:
129+
- forbidigo
124130
# TODO: remove these exceptions by moving the dependency out of experimental/.
125131
- path: cmd/apps/init.go
126132
linters:

acceptance/internal/prepare_server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func isTruePtr(value *bool) bool {
6464
}
6565

6666
func PrepareServerAndClient(t *testing.T, config TestConfig, logRequests bool, outputDir string) (*sdkconfig.Config, iam.User) {
67-
cloudEnv := os.Getenv("CLOUD_ENV")
67+
cloudEnv := env.Get(t.Context(), "CLOUD_ENV")
6868
recordRequests := isTruePtr(config.RecordRequests)
6969

7070
// Use a unique token for each test. This allows us to maintain
@@ -107,7 +107,7 @@ func PrepareServerAndClient(t *testing.T, config TestConfig, logRequests bool, o
107107
// use the default shared server.
108108
if len(config.Server) == 0 && !recordRequests {
109109
cfg := &sdkconfig.Config{
110-
Host: os.Getenv("DATABRICKS_DEFAULT_HOST"),
110+
Host: env.Get(t.Context(), "DATABRICKS_DEFAULT_HOST"),
111111
Token: token,
112112
}
113113

bundle/internal/schema/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ func generateSchema(workdir, outputFile string, docsMode bool) {
206206
annotationsOpenApiOverridesPath := filepath.Join(workdir, "annotations_openapi_overrides.yml")
207207

208208
// Input file, the databricks openapi spec.
209-
inputFile := os.Getenv("DATABRICKS_OPENAPI_SPEC")
209+
inputFile := os.Getenv("DATABRICKS_OPENAPI_SPEC") //nolint:forbidigo // main() entry point, no ctx
210210
if inputFile != "" {
211211
p, err := newParser(inputFile)
212212
if err != nil {

cmd/apps/init.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/databricks/cli/libs/apps/prompt"
2525
"github.com/databricks/cli/libs/cmdctx"
2626
"github.com/databricks/cli/libs/cmdio"
27+
"github.com/databricks/cli/libs/env"
2728
"github.com/databricks/cli/libs/git"
2829
"github.com/databricks/cli/libs/log"
2930
ignore "github.com/sabhiram/go-gitignore"
@@ -553,7 +554,7 @@ func runCreate(ctx context.Context, opts createOptions) error {
553554
// Resolve template path (supports local paths and GitHub URLs)
554555
templateSrc := opts.templatePath
555556
if templateSrc == "" {
556-
templateSrc = os.Getenv(templatePathEnvVar)
557+
templateSrc = env.Get(ctx, templatePathEnvVar)
557558
}
558559

559560
// Resolve the git reference (branch/tag) to use for default appkit template

cmd/apps/manifest.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ import (
99
"path/filepath"
1010

1111
"github.com/databricks/cli/libs/apps/manifest"
12+
"github.com/databricks/cli/libs/env"
1213
"github.com/spf13/cobra"
1314
)
1415

1516
// runManifestOnly resolves the template, loads appkit.plugins.json if present, and prints it to stdout (or a message if not found).
1617
func runManifestOnly(ctx context.Context, templatePath, branch, version string) error {
1718
templateSrc := templatePath
1819
if templateSrc == "" {
19-
templateSrc = os.Getenv(templatePathEnvVar)
20+
templateSrc = env.Get(ctx, templatePathEnvVar)
2021
}
2122
gitRef := branch
2223
usingDefaultTemplate := templateSrc == ""

cmd/auth/login.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"fmt"
77
"io"
8-
"os"
98
"runtime"
109
"strings"
1110
"time"
@@ -249,7 +248,7 @@ depends on the existing profiles you have set in your configuration file
249248
WorkspaceID: authArguments.WorkspaceID,
250249
Experimental_IsUnifiedHost: authArguments.IsUnifiedHost,
251250
ClusterID: clusterID,
252-
ConfigFile: os.Getenv("DATABRICKS_CONFIG_FILE"),
251+
ConfigFile: env.Get(ctx, "DATABRICKS_CONFIG_FILE"),
253252
ServerlessComputeID: serverlessComputeID,
254253
Scopes: scopesList,
255254
}, clearKeys...)

cmd/auth/profiles.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import (
55
"errors"
66
"fmt"
77
"io/fs"
8-
"os"
98
"sync"
109
"time"
1110

1211
"github.com/databricks/cli/libs/cmdio"
1312
"github.com/databricks/cli/libs/databrickscfg/profile"
13+
"github.com/databricks/cli/libs/env"
1414
"github.com/databricks/cli/libs/log"
1515
"github.com/databricks/databricks-sdk-go"
1616
"github.com/databricks/databricks-sdk-go/config"
@@ -37,7 +37,7 @@ func (c *profileMetadata) Load(ctx context.Context, configFilePath string, skipV
3737
Loaders: []config.Loader{config.ConfigFile},
3838
ConfigFile: configFilePath,
3939
Profile: c.Name,
40-
DatabricksCliPath: os.Getenv("DATABRICKS_CLI_PATH"),
40+
DatabricksCliPath: env.Get(ctx, "DATABRICKS_CLI_PATH"),
4141
}
4242
_ = cfg.EnsureResolved()
4343
if cfg.IsAws() {

cmd/auth/token.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/json"
66
"errors"
77
"fmt"
8-
"os"
98
"strings"
109
"time"
1110

@@ -474,7 +473,7 @@ func runInlineLogin(ctx context.Context, profiler profile.Profiler) (string, *pr
474473
AccountID: loginArgs.AccountID,
475474
WorkspaceID: loginArgs.WorkspaceID,
476475
Experimental_IsUnifiedHost: loginArgs.IsUnifiedHost,
477-
ConfigFile: os.Getenv("DATABRICKS_CONFIG_FILE"),
476+
ConfigFile: env.Get(ctx, "DATABRICKS_CONFIG_FILE"),
478477
Scopes: scopesList,
479478
}, clearKeys...)
480479
if err != nil {

cmd/completion/install.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func newInstallCmd() *cobra.Command {
2323
RunE: func(cmd *cobra.Command, args []string) error {
2424
ctx := cmd.Context()
2525

26-
shell, err := libcompletion.DetectShell(shellFlag)
26+
shell, err := libcompletion.DetectShell(ctx, shellFlag)
2727
if err != nil {
2828
return err
2929
}
@@ -37,7 +37,7 @@ func newInstallCmd() *cobra.Command {
3737
displayPath := filepath.ToSlash(filePath)
3838

3939
// Check if already installed — no confirmation needed.
40-
result, err := libcompletion.Status(shell, home)
40+
result, err := libcompletion.Status(ctx, shell, home)
4141
if err != nil {
4242
return err
4343
}
@@ -78,7 +78,7 @@ func newInstallCmd() *cobra.Command {
7878
}
7979
}
8080

81-
_, alreadyInstalled, err := libcompletion.Install(shell, home)
81+
_, alreadyInstalled, err := libcompletion.Install(ctx, shell, home)
8282
if err != nil {
8383
return err
8484
}

cmd/completion/status.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func newStatusCmd() *cobra.Command {
2121
RunE: func(cmd *cobra.Command, args []string) error {
2222
ctx := cmd.Context()
2323

24-
shell, err := libcompletion.DetectShell(shellFlag)
24+
shell, err := libcompletion.DetectShell(ctx, shellFlag)
2525
if err != nil {
2626
return err
2727
}
@@ -31,7 +31,7 @@ func newStatusCmd() *cobra.Command {
3131
return err
3232
}
3333

34-
result, err := libcompletion.Status(shell, home)
34+
result, err := libcompletion.Status(ctx, shell, home)
3535
if err != nil {
3636
return err
3737
}

0 commit comments

Comments
 (0)