From 8275bae0bef584116432ef2f71e7f1eb0918d3f5 Mon Sep 17 00:00:00 2001 From: simonfaltum Date: Tue, 9 Jun 2026 23:22:14 +0200 Subject: [PATCH 1/2] Remove import-time side effects from bundle/config and databrickscfg bundle/config's init() exported DATABRICKS_CLI_PATH into the process environment of every importer, including test binaries and generators. Move the export to main so only the CLI binary itself sets it. libs/databrickscfg's init() flipped the process-global ini.DefaultHeader option at import time. Enable it lazily on first config file write instead, via sync.OnceFunc. Behavior is unchanged for the CLI binary. Co-authored-by: Isaac --- bundle/config/workspace.go | 12 ------------ libs/databrickscfg/ops.go | 16 ++++++++++------ main.go | 11 +++++++++++ main_test.go | 17 +++++++++++++++++ 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/bundle/config/workspace.go b/bundle/config/workspace.go index 9cd397f13aa..1300a87a78c 100644 --- a/bundle/config/workspace.go +++ b/bundle/config/workspace.go @@ -2,8 +2,6 @@ package config import ( "context" - "os" - "path/filepath" "strconv" "github.com/databricks/cli/bundle/env" @@ -209,13 +207,3 @@ func (w *Workspace) Client(ctx context.Context) (*databricks.WorkspaceClient, er return databricks.NewWorkspaceClient((*databricks.Config)(cfg)) } - -func init() { - arg0 := os.Args[0] - - // Configure DATABRICKS_CLI_PATH only if our caller intends to use this specific version of this binary. - // Otherwise, if it is equal to its basename, processes can find it in $PATH. - if arg0 != filepath.Base(arg0) { - os.Setenv("DATABRICKS_CLI_PATH", arg0) - } -} diff --git a/libs/databrickscfg/ops.go b/libs/databrickscfg/ops.go index 452a6d362ab..2eb58c2cc78 100644 --- a/libs/databrickscfg/ops.go +++ b/libs/databrickscfg/ops.go @@ -7,6 +7,7 @@ import ( "io/fs" "os" "strings" + "sync" "github.com/databricks/cli/libs/env" "github.com/databricks/cli/libs/log" @@ -357,7 +358,16 @@ func AuthCredentialKeys() []string { return keys } +// We document databrickscfg files with a [DEFAULT] header and wish to keep it that way. +// This, however, does mean we emit a [DEFAULT] section even if it's empty. +// ini.DefaultHeader is process-global, so it is enabled on first write instead of +// at import time to keep this package free of import side effects. +var enableDefaultHeader = sync.OnceFunc(func() { + ini.DefaultHeader = true +}) + func writeConfigFile(ctx context.Context, configFile *config.File) error { + enableDefaultHeader() section := configFile.Section(ini.DefaultSection) if len(section.Keys()) == 0 && section.Comment == "" { section.Comment = defaultComment @@ -499,9 +509,3 @@ func ValidateConfigAndProfileHost(cfg *config.Config, profile string) error { return nil } - -func init() { - // We document databrickscfg files with a [DEFAULT] header and wish to keep it that way. - // This, however, does mean we emit a [DEFAULT] section even if it's empty. - ini.DefaultHeader = true -} diff --git a/main.go b/main.go index e81dde6946b..6c4dddd40b6 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "context" "os" + "path/filepath" "github.com/databricks/cli/cmd" "github.com/databricks/cli/cmd/root" @@ -13,6 +14,16 @@ import ( ) func main() { + // Configure DATABRICKS_CLI_PATH only if our caller intends to use this specific version of this binary. + // Otherwise, if it is equal to its basename, processes can find it in $PATH. + // This runs in main rather than in a package init so that importing CLI + // packages (e.g. from test binaries or generators) does not mutate the + // process environment. + arg0 := os.Args[0] + if arg0 != filepath.Base(arg0) { + os.Setenv("DATABRICKS_CLI_PATH", arg0) + } + ctx := context.Background() err := root.Execute(ctx, cmd.New(ctx)) if err != nil { diff --git a/main_test.go b/main_test.go index ba40c19746e..22fd09d4a75 100644 --- a/main_test.go +++ b/main_test.go @@ -2,12 +2,14 @@ package main import ( "io/fs" + "os" "path/filepath" "testing" "github.com/databricks/cli/cmd" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golang.org/x/mod/module" ) @@ -26,6 +28,21 @@ func TestCommandsDontUseUnderscoreInName(t *testing.T) { } } +func TestImportDoesNotSetCliPathEnv(t *testing.T) { + // Exporting DATABRICKS_CLI_PATH is done in main, not in a package init, + // so that importing CLI packages (e.g. from test binaries or generators) + // does not mutate the process environment. + // + // This test lives in the main package because this is where + // all commands are imported. + // + // Test binaries run by their absolute path, which is exactly the condition + // under which main exports the variable; an import-time export would + // therefore have set it to this test binary's path by now. + require.NotEqual(t, filepath.Base(os.Args[0]), os.Args[0]) + assert.NotEqual(t, os.Args[0], os.Getenv("DATABRICKS_CLI_PATH")) +} + func TestFilePath(t *testing.T) { // To import this repository as a library, all files must match the // file path constraints made by Go. This test ensures that all files From bdbfcbf5626b67e5cb1903a58fbeebaad4348e17 Mon Sep 17 00:00:00 2001 From: simonfaltum Date: Wed, 10 Jun 2026 07:31:38 +0200 Subject: [PATCH 2/2] Remove redundant comments Co-authored-by: Isaac --- main_test.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/main_test.go b/main_test.go index 22fd09d4a75..0f93f0236bd 100644 --- a/main_test.go +++ b/main_test.go @@ -29,15 +29,8 @@ func TestCommandsDontUseUnderscoreInName(t *testing.T) { } func TestImportDoesNotSetCliPathEnv(t *testing.T) { - // Exporting DATABRICKS_CLI_PATH is done in main, not in a package init, - // so that importing CLI packages (e.g. from test binaries or generators) - // does not mutate the process environment. - // - // This test lives in the main package because this is where - // all commands are imported. - // // Test binaries run by their absolute path, which is exactly the condition - // under which main exports the variable; an import-time export would + // under which main exports DATABRICKS_CLI_PATH; an import-time export would // therefore have set it to this test binary's path by now. require.NotEqual(t, filepath.Base(os.Args[0]), os.Args[0]) assert.NotEqual(t, os.Args[0], os.Getenv("DATABRICKS_CLI_PATH"))