From 2edc0bc725635e6eb2b461053346f4402ad24fba Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 18 Mar 2026 10:55:43 +0100 Subject: [PATCH 1/6] Add DATABRICKS_BUNDLE_ENGINE_DEFAULT env var support Add a new environment variable DATABRICKS_BUNDLE_ENGINE_DEFAULT that sets the default deployment engine. Priority order: state > DATABRICKS_BUNDLE_ENGINE > config > DATABRICKS_BUNDLE_ENGINE_DEFAULT --- .../state/engine_default/databricks.yml | 2 + .../bundle/state/engine_default/out.test.toml | 5 +++ .../bundle/state/engine_default/output.txt | 20 +++++++++ acceptance/bundle/state/engine_default/script | 18 ++++++++ .../bundle/state/engine_default/test.toml | 1 + bundle/config/engine/engine.go | 29 +++++++++--- bundle/config/engine/engine_test.go | 24 ++++++++++ cmd/bundle/utils/process.go | 3 ++ cmd/bundle/utils/resolve_engine_test.go | 45 +++++++++++++++++++ 9 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 acceptance/bundle/state/engine_default/databricks.yml create mode 100644 acceptance/bundle/state/engine_default/out.test.toml create mode 100644 acceptance/bundle/state/engine_default/output.txt create mode 100644 acceptance/bundle/state/engine_default/script create mode 100644 acceptance/bundle/state/engine_default/test.toml create mode 100644 cmd/bundle/utils/resolve_engine_test.go diff --git a/acceptance/bundle/state/engine_default/databricks.yml b/acceptance/bundle/state/engine_default/databricks.yml new file mode 100644 index 0000000000..55beee8c8e --- /dev/null +++ b/acceptance/bundle/state/engine_default/databricks.yml @@ -0,0 +1,2 @@ +bundle: + name: test-engine-default diff --git a/acceptance/bundle/state/engine_default/out.test.toml b/acceptance/bundle/state/engine_default/out.test.toml new file mode 100644 index 0000000000..d560f1de04 --- /dev/null +++ b/acceptance/bundle/state/engine_default/out.test.toml @@ -0,0 +1,5 @@ +Local = true +Cloud = false + +[EnvMatrix] + DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/bundle/state/engine_default/output.txt b/acceptance/bundle/state/engine_default/output.txt new file mode 100644 index 0000000000..a6a1508310 --- /dev/null +++ b/acceptance/bundle/state/engine_default/output.txt @@ -0,0 +1,20 @@ + +=== Default env var matches state: no warning + +>>> DATABRICKS_BUNDLE_ENGINE_DEFAULT=terraform [CLI] bundle debug states +[TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" + +=== Default env var does not match state: state wins silently + +>>> DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct [CLI] bundle debug states +[TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" + +=== DATABRICKS_BUNDLE_ENGINE overrides default + +>>> DATABRICKS_BUNDLE_ENGINE=terraform DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct [CLI] bundle debug states +[TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" + +=== Invalid default env var: error expected + +>>> musterr [CLI] bundle debug states +Error: unexpected setting for DATABRICKS_BUNDLE_ENGINE_DEFAULT="bla" (expected 'terraform' or 'direct') diff --git a/acceptance/bundle/state/engine_default/script b/acceptance/bundle/state/engine_default/script new file mode 100644 index 0000000000..6a5887951b --- /dev/null +++ b/acceptance/bundle/state/engine_default/script @@ -0,0 +1,18 @@ +mkdir -p .databricks/bundle/default/terraform +echo '{"serial": 1, "lineage": "test-lineage"}' > .databricks/bundle/default/terraform/terraform.tfstate + +title 'Default env var matches state: no warning\n' +unset DATABRICKS_BUNDLE_ENGINE +trace DATABRICKS_BUNDLE_ENGINE_DEFAULT=terraform $CLI bundle debug states + +title 'Default env var does not match state: state wins silently\n' +unset DATABRICKS_BUNDLE_ENGINE +trace DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct $CLI bundle debug states + +title 'DATABRICKS_BUNDLE_ENGINE overrides default\n' +trace DATABRICKS_BUNDLE_ENGINE=terraform DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct $CLI bundle debug states + +title 'Invalid default env var: error expected\n' +export DATABRICKS_BUNDLE_ENGINE_DEFAULT=bla +unset DATABRICKS_BUNDLE_ENGINE +trace musterr $CLI bundle debug states diff --git a/acceptance/bundle/state/engine_default/test.toml b/acceptance/bundle/state/engine_default/test.toml new file mode 100644 index 0000000000..601384fdf9 --- /dev/null +++ b/acceptance/bundle/state/engine_default/test.toml @@ -0,0 +1 @@ +Ignore = [".databricks"] diff --git a/bundle/config/engine/engine.go b/bundle/config/engine/engine.go index a24443d579..b98a56b2b3 100644 --- a/bundle/config/engine/engine.go +++ b/bundle/config/engine/engine.go @@ -9,6 +9,10 @@ import ( const EnvVar = "DATABRICKS_BUNDLE_ENGINE" +// EnvVarDefault is the environment variable that sets the default engine type. +// It is only used when neither DATABRICKS_BUNDLE_ENGINE nor the bundle config specifies an engine. +const EnvVarDefault = "DATABRICKS_BUNDLE_ENGINE_DEFAULT" + type EngineType string const ( @@ -46,19 +50,34 @@ func FromEnv(ctx context.Context) (EngineType, error) { // EngineSetting represents a requested engine type along with the source of the request. type EngineSetting struct { - Type EngineType // effective: env var if set, else config - Source string // human-readable source of Type - ConfigType EngineType // from bundle config (EngineNotSet if not configured) + Type EngineType // effective: env var if set, else config + Source string // human-readable source of Type + ConfigType EngineType // from bundle config (EngineNotSet if not configured) + DefaultType EngineType // from DATABRICKS_BUNDLE_ENGINE_DEFAULT (EngineNotSet if not set) } -// SettingFromEnv returns an EngineSetting from the environment variable. +// SettingFromEnv returns an EngineSetting from environment variables. // ConfigType is left as EngineNotSet and populated later by ResolveEngineSetting. func SettingFromEnv(ctx context.Context) (EngineSetting, error) { e, err := FromEnv(ctx) if err != nil { return EngineSetting{}, err } - return EngineSetting{Type: e, Source: EnvVar + " environment variable"}, nil + d, err := defaultFromEnv(ctx) + if err != nil { + return EngineSetting{}, err + } + return EngineSetting{Type: e, Source: EnvVar + " environment variable", DefaultType: d}, nil +} + +// defaultFromEnv returns the engine type from the DATABRICKS_BUNDLE_ENGINE_DEFAULT environment variable. +func defaultFromEnv(ctx context.Context) (EngineType, error) { + value := env.Get(ctx, EnvVarDefault) + e, ok := Parse(value) + if !ok { + return EngineNotSet, fmt.Errorf("unexpected setting for %s=%#v (expected 'terraform' or 'direct')", EnvVarDefault, value) + } + return e, nil } func (e EngineType) ThisOrDefault() EngineType { diff --git a/bundle/config/engine/engine_test.go b/bundle/config/engine/engine_test.go index cf7c409703..e917427e8b 100644 --- a/bundle/config/engine/engine_test.go +++ b/bundle/config/engine/engine_test.go @@ -28,3 +28,27 @@ func TestSettingFromEnvInvalid(t *testing.T) { _, err := SettingFromEnv(ctx) assert.Error(t, err) } + +func TestSettingFromEnvDefault(t *testing.T) { + ctx := env.Set(t.Context(), EnvVarDefault, "direct") + req, err := SettingFromEnv(ctx) + require.NoError(t, err) + assert.Equal(t, EngineNotSet, req.Type) + assert.Equal(t, EngineDirect, req.DefaultType) +} + +func TestSettingFromEnvDefaultInvalid(t *testing.T) { + ctx := env.Set(t.Context(), EnvVarDefault, "invalid") + _, err := SettingFromEnv(ctx) + assert.Error(t, err) +} + +func TestSettingFromEnvBothSet(t *testing.T) { + ctx := t.Context() + ctx = env.Set(ctx, EnvVar, "terraform") + ctx = env.Set(ctx, EnvVarDefault, "direct") + req, err := SettingFromEnv(ctx) + require.NoError(t, err) + assert.Equal(t, EngineTerraform, req.Type) + assert.Equal(t, EngineDirect, req.DefaultType) +} diff --git a/cmd/bundle/utils/process.go b/cmd/bundle/utils/process.go index a09db23c6c..1d7183f0fe 100644 --- a/cmd/bundle/utils/process.go +++ b/cmd/bundle/utils/process.go @@ -315,6 +315,9 @@ func ResolveEngineSetting(b *bundle.Bundle, envSetting engine.EngineSetting) eng } return engine.EngineSetting{Type: configEngine, Source: source, ConfigType: configEngine} } + if envSetting.DefaultType != engine.EngineNotSet { + return engine.EngineSetting{Type: envSetting.DefaultType, Source: engine.EnvVarDefault + " environment variable", ConfigType: configEngine} + } return engine.EngineSetting{} } diff --git a/cmd/bundle/utils/resolve_engine_test.go b/cmd/bundle/utils/resolve_engine_test.go new file mode 100644 index 0000000000..311664c587 --- /dev/null +++ b/cmd/bundle/utils/resolve_engine_test.go @@ -0,0 +1,45 @@ +package utils + +import ( + "testing" + + "github.com/databricks/cli/bundle" + "github.com/databricks/cli/bundle/config" + "github.com/databricks/cli/bundle/config/engine" + "github.com/stretchr/testify/assert" +) + +func TestResolveEngineSettingEnvOverridesAll(t *testing.T) { + b := &bundle.Bundle{Config: config.Root{Bundle: config.Bundle{Engine: engine.EngineDirect}}} + envSetting := engine.EngineSetting{ + Type: engine.EngineTerraform, + Source: engine.EnvVar + " environment variable", + DefaultType: engine.EngineDirect, + } + result := ResolveEngineSetting(b, envSetting) + assert.Equal(t, engine.EngineTerraform, result.Type) + assert.Equal(t, engine.EngineDirect, result.ConfigType) +} + +func TestResolveEngineSettingConfigOverridesDefault(t *testing.T) { + b := &bundle.Bundle{Config: config.Root{Bundle: config.Bundle{Engine: engine.EngineDirect}}} + envSetting := engine.EngineSetting{DefaultType: engine.EngineTerraform} + result := ResolveEngineSetting(b, envSetting) + assert.Equal(t, engine.EngineDirect, result.Type) + assert.Equal(t, engine.EngineDirect, result.ConfigType) +} + +func TestResolveEngineSettingDefaultUsedWhenNothingElseSet(t *testing.T) { + b := &bundle.Bundle{Config: config.Root{}} + envSetting := engine.EngineSetting{DefaultType: engine.EngineDirect} + result := ResolveEngineSetting(b, envSetting) + assert.Equal(t, engine.EngineDirect, result.Type) + assert.Contains(t, result.Source, engine.EnvVarDefault) +} + +func TestResolveEngineSettingNothingSet(t *testing.T) { + b := &bundle.Bundle{Config: config.Root{}} + envSetting := engine.EngineSetting{} + result := ResolveEngineSetting(b, envSetting) + assert.Equal(t, engine.EngineNotSet, result.Type) +} From d7e04a408a602c67d18d40ad951735a2614a004b Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 18 Mar 2026 11:26:34 +0100 Subject: [PATCH 2/6] Simplify engine resolution: merge SettingFromEnv into ResolveEngineSetting Remove the two-phase design where SettingFromEnv read env vars before bundle load and ResolveEngineSetting merged them later. ResolveEngineSetting now takes ctx and reads env vars directly, eliminating SettingFromEnv, defaultFromEnv, and the DefaultType field from EngineSetting. Co-Authored-By: Claude Sonnet 4.6 --- bundle/config/engine/engine.go | 31 ++--------------- bundle/config/engine/engine_test.go | 44 +++++-------------------- cmd/bundle/generate/dashboard.go | 13 +++----- cmd/bundle/run.go | 11 +++---- cmd/bundle/utils/process.go | 42 ++++++++++++++--------- cmd/bundle/utils/resolve_engine_test.go | 39 +++++++++++++++------- 6 files changed, 75 insertions(+), 105 deletions(-) diff --git a/bundle/config/engine/engine.go b/bundle/config/engine/engine.go index b98a56b2b3..ee31a2c66c 100644 --- a/bundle/config/engine/engine.go +++ b/bundle/config/engine/engine.go @@ -50,34 +50,9 @@ func FromEnv(ctx context.Context) (EngineType, error) { // EngineSetting represents a requested engine type along with the source of the request. type EngineSetting struct { - Type EngineType // effective: env var if set, else config - Source string // human-readable source of Type - ConfigType EngineType // from bundle config (EngineNotSet if not configured) - DefaultType EngineType // from DATABRICKS_BUNDLE_ENGINE_DEFAULT (EngineNotSet if not set) -} - -// SettingFromEnv returns an EngineSetting from environment variables. -// ConfigType is left as EngineNotSet and populated later by ResolveEngineSetting. -func SettingFromEnv(ctx context.Context) (EngineSetting, error) { - e, err := FromEnv(ctx) - if err != nil { - return EngineSetting{}, err - } - d, err := defaultFromEnv(ctx) - if err != nil { - return EngineSetting{}, err - } - return EngineSetting{Type: e, Source: EnvVar + " environment variable", DefaultType: d}, nil -} - -// defaultFromEnv returns the engine type from the DATABRICKS_BUNDLE_ENGINE_DEFAULT environment variable. -func defaultFromEnv(ctx context.Context) (EngineType, error) { - value := env.Get(ctx, EnvVarDefault) - e, ok := Parse(value) - if !ok { - return EngineNotSet, fmt.Errorf("unexpected setting for %s=%#v (expected 'terraform' or 'direct')", EnvVarDefault, value) - } - return e, nil + Type EngineType // effective resolved engine + Source string // human-readable source of Type + ConfigType EngineType // from bundle config (EngineNotSet if not configured) } func (e EngineType) ThisOrDefault() EngineType { diff --git a/bundle/config/engine/engine_test.go b/bundle/config/engine/engine_test.go index e917427e8b..03d6608e34 100644 --- a/bundle/config/engine/engine_test.go +++ b/bundle/config/engine/engine_test.go @@ -8,47 +8,21 @@ import ( "github.com/stretchr/testify/require" ) -func TestSettingFromEnv(t *testing.T) { - ctx := t.Context() - ctx = env.Set(ctx, EnvVar, "direct") - req, err := SettingFromEnv(ctx) +func TestFromEnv(t *testing.T) { + ctx := env.Set(t.Context(), EnvVar, "direct") + e, err := FromEnv(ctx) require.NoError(t, err) - assert.Equal(t, EngineDirect, req.Type) - assert.Contains(t, req.Source, EnvVar) + assert.Equal(t, EngineDirect, e) } -func TestSettingFromEnvNotSet(t *testing.T) { - req, err := SettingFromEnv(t.Context()) +func TestFromEnvNotSet(t *testing.T) { + e, err := FromEnv(t.Context()) require.NoError(t, err) - assert.Equal(t, EngineNotSet, req.Type) + assert.Equal(t, EngineNotSet, e) } -func TestSettingFromEnvInvalid(t *testing.T) { +func TestFromEnvInvalid(t *testing.T) { ctx := env.Set(t.Context(), EnvVar, "invalid") - _, err := SettingFromEnv(ctx) + _, err := FromEnv(ctx) assert.Error(t, err) } - -func TestSettingFromEnvDefault(t *testing.T) { - ctx := env.Set(t.Context(), EnvVarDefault, "direct") - req, err := SettingFromEnv(ctx) - require.NoError(t, err) - assert.Equal(t, EngineNotSet, req.Type) - assert.Equal(t, EngineDirect, req.DefaultType) -} - -func TestSettingFromEnvDefaultInvalid(t *testing.T) { - ctx := env.Set(t.Context(), EnvVarDefault, "invalid") - _, err := SettingFromEnv(ctx) - assert.Error(t, err) -} - -func TestSettingFromEnvBothSet(t *testing.T) { - ctx := t.Context() - ctx = env.Set(ctx, EnvVar, "terraform") - ctx = env.Set(ctx, EnvVarDefault, "direct") - req, err := SettingFromEnv(ctx) - require.NoError(t, err) - assert.Equal(t, EngineTerraform, req.Type) - assert.Equal(t, EngineDirect, req.DefaultType) -} diff --git a/cmd/bundle/generate/dashboard.go b/cmd/bundle/generate/dashboard.go index 8b95e63ee6..ce5902cd8e 100644 --- a/cmd/bundle/generate/dashboard.go +++ b/cmd/bundle/generate/dashboard.go @@ -14,7 +14,6 @@ import ( "time" "github.com/databricks/cli/bundle" - "github.com/databricks/cli/bundle/config/engine" "github.com/databricks/cli/bundle/generate" "github.com/databricks/cli/bundle/phases" "github.com/databricks/cli/bundle/resources" @@ -374,18 +373,16 @@ func (d *dashboard) initialize(ctx context.Context, b *bundle.Bundle) { } func (d *dashboard) runForResource(ctx context.Context, b *bundle.Bundle) { - envEngine, err := engine.SettingFromEnv(ctx) - if err != nil { - logdiag.LogError(ctx, err) - return - } - phases.Initialize(ctx, b) if logdiag.HasError(ctx) { return } - requiredEngine := utils.ResolveEngineSetting(b, envEngine) + requiredEngine, err := utils.ResolveEngineSetting(ctx, b) + if err != nil { + logdiag.LogError(ctx, err) + return + } ctx, stateDesc := statemgmt.PullResourcesState(ctx, b, statemgmt.AlwaysPull(true), requiredEngine) if logdiag.HasError(ctx) { return diff --git a/cmd/bundle/run.go b/cmd/bundle/run.go index a9145461c8..ec4d894b1f 100644 --- a/cmd/bundle/run.go +++ b/cmd/bundle/run.go @@ -8,7 +8,6 @@ import ( "os" "github.com/databricks/cli/bundle" - "github.com/databricks/cli/bundle/config/engine" "github.com/databricks/cli/bundle/env" "github.com/databricks/cli/bundle/phases" "github.com/databricks/cli/bundle/resources" @@ -133,11 +132,6 @@ Example usage: cmd.Flags().BoolVar(&restart, "restart", false, "Restart the run if it is already running.") cmd.RunE = func(cmd *cobra.Command, args []string) error { - envEngine, err := engine.SettingFromEnv(cmd.Context()) - if err != nil { - return err - } - b, err := utils.ProcessBundle(cmd, utils.ProcessOptions{ SkipInitialize: true, }) @@ -172,7 +166,10 @@ Example usage: return executeScript(content, cmd, b) } - requiredEngine := utils.ResolveEngineSetting(b, envEngine) + requiredEngine, err := utils.ResolveEngineSetting(ctx, b) + if err != nil { + return err + } ctx, stateDesc := statemgmt.PullResourcesState(ctx, b, statemgmt.AlwaysPull(true), requiredEngine) if logdiag.HasError(ctx) { return root.ErrAlreadyPrinted diff --git a/cmd/bundle/utils/process.go b/cmd/bundle/utils/process.go index 1d7183f0fe..ec6a4f133b 100644 --- a/cmd/bundle/utils/process.go +++ b/cmd/bundle/utils/process.go @@ -19,6 +19,7 @@ import ( "github.com/databricks/cli/internal/build" "github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/dyn" + "github.com/databricks/cli/libs/env" "github.com/databricks/cli/libs/log" "github.com/databricks/cli/libs/logdiag" "github.com/databricks/cli/libs/sync" @@ -92,11 +93,6 @@ func ProcessBundleRet(cmd *cobra.Command, opts ProcessOptions) (*bundle.Bundle, cmd.SetContext(ctx) } - envEngine, err := engine.SettingFromEnv(ctx) - if err != nil { - return nil, nil, err - } - // Load bundle config and apply target b := root.MustConfigureBundle(cmd) if logdiag.HasError(ctx) { @@ -157,7 +153,10 @@ func ProcessBundleRet(cmd *cobra.Command, opts ProcessOptions) (*bundle.Bundle, shouldReadState := opts.ReadState || opts.AlwaysPull || opts.InitIDs || opts.ErrorOnEmptyState || opts.PreDeployChecks || opts.Deploy || opts.ReadPlanPath != "" if shouldReadState { - requiredEngine := ResolveEngineSetting(b, envEngine) + requiredEngine, err := ResolveEngineSetting(ctx, b) + if err != nil { + return b, nil, err + } // PullResourcesState depends on stateFiler which needs b.Config.Workspace.StatePath which is set in phases.Initialize ctx, stateDesc = statemgmt.PullResourcesState(ctx, b, statemgmt.AlwaysPull(opts.AlwaysPull), requiredEngine) @@ -299,13 +298,19 @@ func ProcessBundleRet(cmd *cobra.Command, opts ProcessOptions) (*bundle.Bundle, return b, stateDesc, nil } -// ResolveEngineSetting combines the env var engine with the bundle config engine setting. -// Environment variable takes priority over config. ConfigType always reflects the config value. -func ResolveEngineSetting(b *bundle.Bundle, envSetting engine.EngineSetting) engine.EngineSetting { +// ResolveEngineSetting determines the effective engine setting by combining env vars and bundle config. +// Priority: DATABRICKS_BUNDLE_ENGINE > bundle.engine config > DATABRICKS_BUNDLE_ENGINE_DEFAULT. +func ResolveEngineSetting(ctx context.Context, b *bundle.Bundle) (engine.EngineSetting, error) { configEngine := b.Config.Bundle.Engine - if envSetting.Type != engine.EngineNotSet { - return engine.EngineSetting{Type: envSetting.Type, Source: envSetting.Source, ConfigType: configEngine} + + envEngine, err := engine.FromEnv(ctx) + if err != nil { + return engine.EngineSetting{}, err + } + if envEngine != engine.EngineNotSet { + return engine.EngineSetting{Type: envEngine, Source: engine.EnvVar + " environment variable", ConfigType: configEngine}, nil } + if configEngine != engine.EngineNotSet { source := "bundle.engine setting" v := dyn.GetValue(b.Config.Value(), "bundle.engine") @@ -313,12 +318,19 @@ func ResolveEngineSetting(b *bundle.Bundle, envSetting engine.EngineSetting) eng loc := locs[0] source = fmt.Sprintf("bundle.engine setting at %s:%d:%d", filepath.ToSlash(loc.File), loc.Line, loc.Column) } - return engine.EngineSetting{Type: configEngine, Source: source, ConfigType: configEngine} + return engine.EngineSetting{Type: configEngine, Source: source, ConfigType: configEngine}, nil } - if envSetting.DefaultType != engine.EngineNotSet { - return engine.EngineSetting{Type: envSetting.DefaultType, Source: engine.EnvVarDefault + " environment variable", ConfigType: configEngine} + + defaultValue := env.Get(ctx, engine.EnvVarDefault) + defaultEngine, ok := engine.Parse(defaultValue) + if !ok { + return engine.EngineSetting{}, fmt.Errorf("unexpected setting for %s=%#v (expected 'terraform' or 'direct')", engine.EnvVarDefault, defaultValue) + } + if defaultEngine != engine.EngineNotSet { + return engine.EngineSetting{Type: defaultEngine, Source: engine.EnvVarDefault + " environment variable", ConfigType: configEngine}, nil } - return engine.EngineSetting{} + + return engine.EngineSetting{}, nil } func rejectDefinitions(ctx context.Context, b *bundle.Bundle) { diff --git a/cmd/bundle/utils/resolve_engine_test.go b/cmd/bundle/utils/resolve_engine_test.go index 311664c587..c3f9d29b7d 100644 --- a/cmd/bundle/utils/resolve_engine_test.go +++ b/cmd/bundle/utils/resolve_engine_test.go @@ -6,40 +6,55 @@ import ( "github.com/databricks/cli/bundle" "github.com/databricks/cli/bundle/config" "github.com/databricks/cli/bundle/config/engine" + "github.com/databricks/cli/libs/env" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestResolveEngineSettingEnvOverridesAll(t *testing.T) { + ctx := env.Set(t.Context(), engine.EnvVar, "terraform") b := &bundle.Bundle{Config: config.Root{Bundle: config.Bundle{Engine: engine.EngineDirect}}} - envSetting := engine.EngineSetting{ - Type: engine.EngineTerraform, - Source: engine.EnvVar + " environment variable", - DefaultType: engine.EngineDirect, - } - result := ResolveEngineSetting(b, envSetting) + result, err := ResolveEngineSetting(ctx, b) + require.NoError(t, err) assert.Equal(t, engine.EngineTerraform, result.Type) assert.Equal(t, engine.EngineDirect, result.ConfigType) } func TestResolveEngineSettingConfigOverridesDefault(t *testing.T) { + ctx := env.Set(t.Context(), engine.EnvVarDefault, "terraform") b := &bundle.Bundle{Config: config.Root{Bundle: config.Bundle{Engine: engine.EngineDirect}}} - envSetting := engine.EngineSetting{DefaultType: engine.EngineTerraform} - result := ResolveEngineSetting(b, envSetting) + result, err := ResolveEngineSetting(ctx, b) + require.NoError(t, err) assert.Equal(t, engine.EngineDirect, result.Type) assert.Equal(t, engine.EngineDirect, result.ConfigType) } func TestResolveEngineSettingDefaultUsedWhenNothingElseSet(t *testing.T) { + ctx := env.Set(t.Context(), engine.EnvVarDefault, "direct") b := &bundle.Bundle{Config: config.Root{}} - envSetting := engine.EngineSetting{DefaultType: engine.EngineDirect} - result := ResolveEngineSetting(b, envSetting) + result, err := ResolveEngineSetting(ctx, b) + require.NoError(t, err) assert.Equal(t, engine.EngineDirect, result.Type) assert.Contains(t, result.Source, engine.EnvVarDefault) } func TestResolveEngineSettingNothingSet(t *testing.T) { b := &bundle.Bundle{Config: config.Root{}} - envSetting := engine.EngineSetting{} - result := ResolveEngineSetting(b, envSetting) + result, err := ResolveEngineSetting(t.Context(), b) + require.NoError(t, err) assert.Equal(t, engine.EngineNotSet, result.Type) } + +func TestResolveEngineSettingInvalidEnvVar(t *testing.T) { + ctx := env.Set(t.Context(), engine.EnvVar, "invalid") + b := &bundle.Bundle{Config: config.Root{}} + _, err := ResolveEngineSetting(ctx, b) + assert.Error(t, err) +} + +func TestResolveEngineSettingInvalidDefaultEnvVar(t *testing.T) { + ctx := env.Set(t.Context(), engine.EnvVarDefault, "invalid") + b := &bundle.Bundle{Config: config.Root{}} + _, err := ResolveEngineSetting(ctx, b) + assert.Error(t, err) +} From 90f59263f8f4b37bb9525ebd19704b8d6df53206 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 18 Mar 2026 11:46:43 +0100 Subject: [PATCH 3/6] Fix engine_default acceptance test: split into separate cases per engine The single-directory test was broken: the first deploy (terraform) created remote state on the mock server, which persisted after `rm -fr .databricks`. The second deploy found that remote state and the state-priority logic overrode DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct, causing it to use terraform. Split into two subdirectories (direct/ and terraform/), each running a single first deploy with no prior state. Each gets a fresh mock server. Co-Authored-By: Claude Sonnet 4.6 --- .../state/engine_default/databricks.yml | 2 -- .../engine_default/direct/databricks.yml | 7 +++++++ .../state/engine_default/direct/out.test.toml | 5 +++++ .../state/engine_default/direct/output.txt | 7 +++++++ .../bundle/state/engine_default/direct/script | 3 +++ .../state/engine_default/direct/test.toml | 2 ++ .../bundle/state/engine_default/out.test.toml | 5 ----- .../bundle/state/engine_default/output.txt | 20 ------------------- acceptance/bundle/state/engine_default/script | 18 ----------------- .../engine_default/terraform/databricks.yml | 7 +++++++ .../engine_default/terraform/out.test.toml | 5 +++++ .../state/engine_default/terraform/output.txt | 7 +++++++ .../state/engine_default/terraform/script | 3 +++ .../state/engine_default/terraform/test.toml | 2 ++ .../bundle/state/engine_default/test.toml | 1 - 15 files changed, 48 insertions(+), 46 deletions(-) delete mode 100644 acceptance/bundle/state/engine_default/databricks.yml create mode 100644 acceptance/bundle/state/engine_default/direct/databricks.yml create mode 100644 acceptance/bundle/state/engine_default/direct/out.test.toml create mode 100644 acceptance/bundle/state/engine_default/direct/output.txt create mode 100644 acceptance/bundle/state/engine_default/direct/script create mode 100644 acceptance/bundle/state/engine_default/direct/test.toml delete mode 100644 acceptance/bundle/state/engine_default/out.test.toml delete mode 100644 acceptance/bundle/state/engine_default/output.txt delete mode 100644 acceptance/bundle/state/engine_default/script create mode 100644 acceptance/bundle/state/engine_default/terraform/databricks.yml create mode 100644 acceptance/bundle/state/engine_default/terraform/out.test.toml create mode 100644 acceptance/bundle/state/engine_default/terraform/output.txt create mode 100644 acceptance/bundle/state/engine_default/terraform/script create mode 100644 acceptance/bundle/state/engine_default/terraform/test.toml delete mode 100644 acceptance/bundle/state/engine_default/test.toml diff --git a/acceptance/bundle/state/engine_default/databricks.yml b/acceptance/bundle/state/engine_default/databricks.yml deleted file mode 100644 index 55beee8c8e..0000000000 --- a/acceptance/bundle/state/engine_default/databricks.yml +++ /dev/null @@ -1,2 +0,0 @@ -bundle: - name: test-engine-default diff --git a/acceptance/bundle/state/engine_default/direct/databricks.yml b/acceptance/bundle/state/engine_default/direct/databricks.yml new file mode 100644 index 0000000000..638ee3c8c1 --- /dev/null +++ b/acceptance/bundle/state/engine_default/direct/databricks.yml @@ -0,0 +1,7 @@ +bundle: + name: test-engine-default + +resources: + jobs: + foo: + name: foo diff --git a/acceptance/bundle/state/engine_default/direct/out.test.toml b/acceptance/bundle/state/engine_default/direct/out.test.toml new file mode 100644 index 0000000000..54146af564 --- /dev/null +++ b/acceptance/bundle/state/engine_default/direct/out.test.toml @@ -0,0 +1,5 @@ +Local = true +Cloud = false + +[EnvMatrix] + DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/state/engine_default/direct/output.txt b/acceptance/bundle/state/engine_default/direct/output.txt new file mode 100644 index 0000000000..29263635cd --- /dev/null +++ b/acceptance/bundle/state/engine_default/direct/output.txt @@ -0,0 +1,7 @@ + +>>> DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-engine-default/default/files... +Deploying resources... +Updating deployment state... +Deployment complete! +.databricks/bundle/default/resources.json diff --git a/acceptance/bundle/state/engine_default/direct/script b/acceptance/bundle/state/engine_default/direct/script new file mode 100644 index 0000000000..cec85ee2fb --- /dev/null +++ b/acceptance/bundle/state/engine_default/direct/script @@ -0,0 +1,3 @@ +unset DATABRICKS_BUNDLE_ENGINE +trace DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct $CLI bundle deploy +find .databricks | grep -E 'resources.json|tfstate' | contains.py "!tfstate" "resources.json" diff --git a/acceptance/bundle/state/engine_default/direct/test.toml b/acceptance/bundle/state/engine_default/direct/test.toml new file mode 100644 index 0000000000..c3f6fd319d --- /dev/null +++ b/acceptance/bundle/state/engine_default/direct/test.toml @@ -0,0 +1,2 @@ +Ignore = [".databricks"] +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/state/engine_default/out.test.toml b/acceptance/bundle/state/engine_default/out.test.toml deleted file mode 100644 index d560f1de04..0000000000 --- a/acceptance/bundle/state/engine_default/out.test.toml +++ /dev/null @@ -1,5 +0,0 @@ -Local = true -Cloud = false - -[EnvMatrix] - DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/bundle/state/engine_default/output.txt b/acceptance/bundle/state/engine_default/output.txt deleted file mode 100644 index a6a1508310..0000000000 --- a/acceptance/bundle/state/engine_default/output.txt +++ /dev/null @@ -1,20 +0,0 @@ - -=== Default env var matches state: no warning - ->>> DATABRICKS_BUNDLE_ENGINE_DEFAULT=terraform [CLI] bundle debug states -[TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" - -=== Default env var does not match state: state wins silently - ->>> DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct [CLI] bundle debug states -[TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" - -=== DATABRICKS_BUNDLE_ENGINE overrides default - ->>> DATABRICKS_BUNDLE_ENGINE=terraform DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct [CLI] bundle debug states -[TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" - -=== Invalid default env var: error expected - ->>> musterr [CLI] bundle debug states -Error: unexpected setting for DATABRICKS_BUNDLE_ENGINE_DEFAULT="bla" (expected 'terraform' or 'direct') diff --git a/acceptance/bundle/state/engine_default/script b/acceptance/bundle/state/engine_default/script deleted file mode 100644 index 6a5887951b..0000000000 --- a/acceptance/bundle/state/engine_default/script +++ /dev/null @@ -1,18 +0,0 @@ -mkdir -p .databricks/bundle/default/terraform -echo '{"serial": 1, "lineage": "test-lineage"}' > .databricks/bundle/default/terraform/terraform.tfstate - -title 'Default env var matches state: no warning\n' -unset DATABRICKS_BUNDLE_ENGINE -trace DATABRICKS_BUNDLE_ENGINE_DEFAULT=terraform $CLI bundle debug states - -title 'Default env var does not match state: state wins silently\n' -unset DATABRICKS_BUNDLE_ENGINE -trace DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct $CLI bundle debug states - -title 'DATABRICKS_BUNDLE_ENGINE overrides default\n' -trace DATABRICKS_BUNDLE_ENGINE=terraform DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct $CLI bundle debug states - -title 'Invalid default env var: error expected\n' -export DATABRICKS_BUNDLE_ENGINE_DEFAULT=bla -unset DATABRICKS_BUNDLE_ENGINE -trace musterr $CLI bundle debug states diff --git a/acceptance/bundle/state/engine_default/terraform/databricks.yml b/acceptance/bundle/state/engine_default/terraform/databricks.yml new file mode 100644 index 0000000000..638ee3c8c1 --- /dev/null +++ b/acceptance/bundle/state/engine_default/terraform/databricks.yml @@ -0,0 +1,7 @@ +bundle: + name: test-engine-default + +resources: + jobs: + foo: + name: foo diff --git a/acceptance/bundle/state/engine_default/terraform/out.test.toml b/acceptance/bundle/state/engine_default/terraform/out.test.toml new file mode 100644 index 0000000000..54146af564 --- /dev/null +++ b/acceptance/bundle/state/engine_default/terraform/out.test.toml @@ -0,0 +1,5 @@ +Local = true +Cloud = false + +[EnvMatrix] + DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/state/engine_default/terraform/output.txt b/acceptance/bundle/state/engine_default/terraform/output.txt new file mode 100644 index 0000000000..c39c8ac7d5 --- /dev/null +++ b/acceptance/bundle/state/engine_default/terraform/output.txt @@ -0,0 +1,7 @@ + +>>> DATABRICKS_BUNDLE_ENGINE_DEFAULT=terraform [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-engine-default/default/files... +Deploying resources... +Updating deployment state... +Deployment complete! +.databricks/bundle/default/terraform/terraform.tfstate diff --git a/acceptance/bundle/state/engine_default/terraform/script b/acceptance/bundle/state/engine_default/terraform/script new file mode 100644 index 0000000000..dc3d7a530f --- /dev/null +++ b/acceptance/bundle/state/engine_default/terraform/script @@ -0,0 +1,3 @@ +unset DATABRICKS_BUNDLE_ENGINE +trace DATABRICKS_BUNDLE_ENGINE_DEFAULT=terraform $CLI bundle deploy +find .databricks | grep -E 'resources.json|tfstate' | contains.py "tfstate" "!resources.json" diff --git a/acceptance/bundle/state/engine_default/terraform/test.toml b/acceptance/bundle/state/engine_default/terraform/test.toml new file mode 100644 index 0000000000..c3f6fd319d --- /dev/null +++ b/acceptance/bundle/state/engine_default/terraform/test.toml @@ -0,0 +1,2 @@ +Ignore = [".databricks"] +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/state/engine_default/test.toml b/acceptance/bundle/state/engine_default/test.toml deleted file mode 100644 index 601384fdf9..0000000000 --- a/acceptance/bundle/state/engine_default/test.toml +++ /dev/null @@ -1 +0,0 @@ -Ignore = [".databricks"] From 6e76d80c879d86e8802e058847d71d9e91197d81 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 18 Mar 2026 12:10:07 +0100 Subject: [PATCH 4/6] Remove DATABRICKS_BUNDLE_ENGINE_DEFAULT; make bundle.engine take priority Remove the DATABRICKS_BUNDLE_ENGINE_DEFAULT env var entirely. Change engine resolution priority to: bundle.engine config > DATABRICKS_BUNDLE_ENGINE env var > built-in default (terraform). This means an explicit bundle config always wins, and the env var acts as a fallback when no config is present. A side-effect of the new priority: an invalid DATABRICKS_BUNDLE_ENGINE is silently ignored when bundle.engine is set in config. Remove the engine_default acceptance tests (tested the removed env var). Update engine_mismatch to drop cases that tested env-var-overrides-config (no longer possible) and add a case showing the invalid env var is ignored when config is set. Remove bundle validate from bad_env since ResolveEngineSetting is not called during validate. Co-Authored-By: Claude Sonnet 4.6 --- acceptance/bundle/state/bad_env/output.txt | 5 ---- acceptance/bundle/state/bad_env/script | 1 - .../engine_default/direct/databricks.yml | 7 ----- .../state/engine_default/direct/out.test.toml | 5 ---- .../state/engine_default/direct/output.txt | 7 ----- .../bundle/state/engine_default/direct/script | 3 -- .../state/engine_default/direct/test.toml | 2 -- .../engine_default/terraform/databricks.yml | 7 ----- .../engine_default/terraform/out.test.toml | 5 ---- .../state/engine_default/terraform/output.txt | 7 ----- .../state/engine_default/terraform/script | 3 -- .../state/engine_default/terraform/test.toml | 2 -- .../bundle/state/engine_mismatch/output.txt | 16 ++--------- .../bundle/state/engine_mismatch/script | 11 ++------ bundle/config/engine/engine.go | 4 --- cmd/bundle/utils/process.go | 24 +++++----------- cmd/bundle/utils/resolve_engine_test.go | 28 +++++++------------ 17 files changed, 22 insertions(+), 115 deletions(-) delete mode 100644 acceptance/bundle/state/engine_default/direct/databricks.yml delete mode 100644 acceptance/bundle/state/engine_default/direct/out.test.toml delete mode 100644 acceptance/bundle/state/engine_default/direct/output.txt delete mode 100644 acceptance/bundle/state/engine_default/direct/script delete mode 100644 acceptance/bundle/state/engine_default/direct/test.toml delete mode 100644 acceptance/bundle/state/engine_default/terraform/databricks.yml delete mode 100644 acceptance/bundle/state/engine_default/terraform/out.test.toml delete mode 100644 acceptance/bundle/state/engine_default/terraform/output.txt delete mode 100644 acceptance/bundle/state/engine_default/terraform/script delete mode 100644 acceptance/bundle/state/engine_default/terraform/test.toml diff --git a/acceptance/bundle/state/bad_env/output.txt b/acceptance/bundle/state/bad_env/output.txt index a77cd778d0..5a88b62f95 100644 --- a/acceptance/bundle/state/bad_env/output.txt +++ b/acceptance/bundle/state/bad_env/output.txt @@ -10,8 +10,3 @@ Error: unexpected setting for DATABRICKS_BUNDLE_ENGINE="abc" (expected 'terrafor >>> musterr [CLI] bundle destroy --auto-approve Error: unexpected setting for DATABRICKS_BUNDLE_ENGINE="abc" (expected 'terraform' or 'direct') - ->>> musterr [CLI] bundle validate -Error: unexpected setting for DATABRICKS_BUNDLE_ENGINE="abc" (expected 'terraform' or 'direct') - -Found 1 error diff --git a/acceptance/bundle/state/bad_env/script b/acceptance/bundle/state/bad_env/script index 5f27e956d6..fce3a3a0f8 100644 --- a/acceptance/bundle/state/bad_env/script +++ b/acceptance/bundle/state/bad_env/script @@ -3,4 +3,3 @@ trace musterr $CLI bundle plan trace musterr $CLI bundle deploy trace musterr $CLI bundle summary trace musterr $CLI bundle destroy --auto-approve -trace musterr $CLI bundle validate diff --git a/acceptance/bundle/state/engine_default/direct/databricks.yml b/acceptance/bundle/state/engine_default/direct/databricks.yml deleted file mode 100644 index 638ee3c8c1..0000000000 --- a/acceptance/bundle/state/engine_default/direct/databricks.yml +++ /dev/null @@ -1,7 +0,0 @@ -bundle: - name: test-engine-default - -resources: - jobs: - foo: - name: foo diff --git a/acceptance/bundle/state/engine_default/direct/out.test.toml b/acceptance/bundle/state/engine_default/direct/out.test.toml deleted file mode 100644 index 54146af564..0000000000 --- a/acceptance/bundle/state/engine_default/direct/out.test.toml +++ /dev/null @@ -1,5 +0,0 @@ -Local = true -Cloud = false - -[EnvMatrix] - DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/state/engine_default/direct/output.txt b/acceptance/bundle/state/engine_default/direct/output.txt deleted file mode 100644 index 29263635cd..0000000000 --- a/acceptance/bundle/state/engine_default/direct/output.txt +++ /dev/null @@ -1,7 +0,0 @@ - ->>> DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct [CLI] bundle deploy -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-engine-default/default/files... -Deploying resources... -Updating deployment state... -Deployment complete! -.databricks/bundle/default/resources.json diff --git a/acceptance/bundle/state/engine_default/direct/script b/acceptance/bundle/state/engine_default/direct/script deleted file mode 100644 index cec85ee2fb..0000000000 --- a/acceptance/bundle/state/engine_default/direct/script +++ /dev/null @@ -1,3 +0,0 @@ -unset DATABRICKS_BUNDLE_ENGINE -trace DATABRICKS_BUNDLE_ENGINE_DEFAULT=direct $CLI bundle deploy -find .databricks | grep -E 'resources.json|tfstate' | contains.py "!tfstate" "resources.json" diff --git a/acceptance/bundle/state/engine_default/direct/test.toml b/acceptance/bundle/state/engine_default/direct/test.toml deleted file mode 100644 index c3f6fd319d..0000000000 --- a/acceptance/bundle/state/engine_default/direct/test.toml +++ /dev/null @@ -1,2 +0,0 @@ -Ignore = [".databricks"] -EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/state/engine_default/terraform/databricks.yml b/acceptance/bundle/state/engine_default/terraform/databricks.yml deleted file mode 100644 index 638ee3c8c1..0000000000 --- a/acceptance/bundle/state/engine_default/terraform/databricks.yml +++ /dev/null @@ -1,7 +0,0 @@ -bundle: - name: test-engine-default - -resources: - jobs: - foo: - name: foo diff --git a/acceptance/bundle/state/engine_default/terraform/out.test.toml b/acceptance/bundle/state/engine_default/terraform/out.test.toml deleted file mode 100644 index 54146af564..0000000000 --- a/acceptance/bundle/state/engine_default/terraform/out.test.toml +++ /dev/null @@ -1,5 +0,0 @@ -Local = true -Cloud = false - -[EnvMatrix] - DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/state/engine_default/terraform/output.txt b/acceptance/bundle/state/engine_default/terraform/output.txt deleted file mode 100644 index c39c8ac7d5..0000000000 --- a/acceptance/bundle/state/engine_default/terraform/output.txt +++ /dev/null @@ -1,7 +0,0 @@ - ->>> DATABRICKS_BUNDLE_ENGINE_DEFAULT=terraform [CLI] bundle deploy -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-engine-default/default/files... -Deploying resources... -Updating deployment state... -Deployment complete! -.databricks/bundle/default/terraform/terraform.tfstate diff --git a/acceptance/bundle/state/engine_default/terraform/script b/acceptance/bundle/state/engine_default/terraform/script deleted file mode 100644 index dc3d7a530f..0000000000 --- a/acceptance/bundle/state/engine_default/terraform/script +++ /dev/null @@ -1,3 +0,0 @@ -unset DATABRICKS_BUNDLE_ENGINE -trace DATABRICKS_BUNDLE_ENGINE_DEFAULT=terraform $CLI bundle deploy -find .databricks | grep -E 'resources.json|tfstate' | contains.py "tfstate" "!resources.json" diff --git a/acceptance/bundle/state/engine_default/terraform/test.toml b/acceptance/bundle/state/engine_default/terraform/test.toml deleted file mode 100644 index c3f6fd319d..0000000000 --- a/acceptance/bundle/state/engine_default/terraform/test.toml +++ /dev/null @@ -1,2 +0,0 @@ -Ignore = [".databricks"] -EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/state/engine_mismatch/output.txt b/acceptance/bundle/state/engine_mismatch/output.txt index fba64dfff1..365f4ef27a 100644 --- a/acceptance/bundle/state/engine_mismatch/output.txt +++ b/acceptance/bundle/state/engine_mismatch/output.txt @@ -9,22 +9,12 @@ Available state files: [TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" -=== Env var confirms config, both mismatch state: warning expected +=== Invalid env var with config set: no error, config takes priority ->>> DATABRICKS_BUNDLE_ENGINE=direct [CLI] bundle debug states -Warning: Deployment engine "direct" configured in DATABRICKS_BUNDLE_ENGINE environment variable does not match the existing state (engine "terraform"). Using "terraform" engine from the existing state. +>>> DATABRICKS_BUNDLE_ENGINE=bla [CLI] bundle debug states +Warning: Deployment engine "direct" configured in bundle.engine setting at [TEST_TMP_DIR]/databricks.yml:3:11 does not match the existing state (engine "terraform"). Using "terraform" engine from the existing state. Available state files: - [TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" [TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" - -=== Env var overrides config to match state: no warning expected - ->>> DATABRICKS_BUNDLE_ENGINE=terraform [CLI] bundle debug states -[TEST_TMP_DIR]/.databricks/bundle/default/terraform/terraform.tfstate: local terraform state serial=1 lineage="test-lineage" - -=== Invalid env var: error expected - ->>> musterr [CLI] bundle debug states -Error: unexpected setting for DATABRICKS_BUNDLE_ENGINE="bla" (expected 'terraform' or 'direct') diff --git a/acceptance/bundle/state/engine_mismatch/script b/acceptance/bundle/state/engine_mismatch/script index 762bc16426..4486677247 100644 --- a/acceptance/bundle/state/engine_mismatch/script +++ b/acceptance/bundle/state/engine_mismatch/script @@ -5,12 +5,5 @@ title 'Config mismatch with state: warning expected\n' unset DATABRICKS_BUNDLE_ENGINE trace $CLI bundle debug states -title 'Env var confirms config, both mismatch state: warning expected\n' -trace DATABRICKS_BUNDLE_ENGINE=direct $CLI bundle debug states - -title 'Env var overrides config to match state: no warning expected\n' -trace DATABRICKS_BUNDLE_ENGINE=terraform $CLI bundle debug states - -title 'Invalid env var: error expected\n' -export DATABRICKS_BUNDLE_ENGINE=bla -trace musterr $CLI bundle debug states +title 'Invalid env var with config set: no error, config takes priority\n' +trace DATABRICKS_BUNDLE_ENGINE=bla $CLI bundle debug states diff --git a/bundle/config/engine/engine.go b/bundle/config/engine/engine.go index ee31a2c66c..c2c251e8f9 100644 --- a/bundle/config/engine/engine.go +++ b/bundle/config/engine/engine.go @@ -9,10 +9,6 @@ import ( const EnvVar = "DATABRICKS_BUNDLE_ENGINE" -// EnvVarDefault is the environment variable that sets the default engine type. -// It is only used when neither DATABRICKS_BUNDLE_ENGINE nor the bundle config specifies an engine. -const EnvVarDefault = "DATABRICKS_BUNDLE_ENGINE_DEFAULT" - type EngineType string const ( diff --git a/cmd/bundle/utils/process.go b/cmd/bundle/utils/process.go index ec6a4f133b..8390548912 100644 --- a/cmd/bundle/utils/process.go +++ b/cmd/bundle/utils/process.go @@ -19,7 +19,6 @@ import ( "github.com/databricks/cli/internal/build" "github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/dyn" - "github.com/databricks/cli/libs/env" "github.com/databricks/cli/libs/log" "github.com/databricks/cli/libs/logdiag" "github.com/databricks/cli/libs/sync" @@ -298,19 +297,11 @@ func ProcessBundleRet(cmd *cobra.Command, opts ProcessOptions) (*bundle.Bundle, return b, stateDesc, nil } -// ResolveEngineSetting determines the effective engine setting by combining env vars and bundle config. -// Priority: DATABRICKS_BUNDLE_ENGINE > bundle.engine config > DATABRICKS_BUNDLE_ENGINE_DEFAULT. +// ResolveEngineSetting determines the effective engine setting by combining bundle config and env var. +// Priority: bundle.engine config > DATABRICKS_BUNDLE_ENGINE env var. func ResolveEngineSetting(ctx context.Context, b *bundle.Bundle) (engine.EngineSetting, error) { configEngine := b.Config.Bundle.Engine - envEngine, err := engine.FromEnv(ctx) - if err != nil { - return engine.EngineSetting{}, err - } - if envEngine != engine.EngineNotSet { - return engine.EngineSetting{Type: envEngine, Source: engine.EnvVar + " environment variable", ConfigType: configEngine}, nil - } - if configEngine != engine.EngineNotSet { source := "bundle.engine setting" v := dyn.GetValue(b.Config.Value(), "bundle.engine") @@ -321,13 +312,12 @@ func ResolveEngineSetting(ctx context.Context, b *bundle.Bundle) (engine.EngineS return engine.EngineSetting{Type: configEngine, Source: source, ConfigType: configEngine}, nil } - defaultValue := env.Get(ctx, engine.EnvVarDefault) - defaultEngine, ok := engine.Parse(defaultValue) - if !ok { - return engine.EngineSetting{}, fmt.Errorf("unexpected setting for %s=%#v (expected 'terraform' or 'direct')", engine.EnvVarDefault, defaultValue) + envEngine, err := engine.FromEnv(ctx) + if err != nil { + return engine.EngineSetting{}, err } - if defaultEngine != engine.EngineNotSet { - return engine.EngineSetting{Type: defaultEngine, Source: engine.EnvVarDefault + " environment variable", ConfigType: configEngine}, nil + if envEngine != engine.EngineNotSet { + return engine.EngineSetting{Type: envEngine, Source: engine.EnvVar + " environment variable"}, nil } return engine.EngineSetting{}, nil diff --git a/cmd/bundle/utils/resolve_engine_test.go b/cmd/bundle/utils/resolve_engine_test.go index c3f9d29b7d..feca507433 100644 --- a/cmd/bundle/utils/resolve_engine_test.go +++ b/cmd/bundle/utils/resolve_engine_test.go @@ -11,31 +11,22 @@ import ( "github.com/stretchr/testify/require" ) -func TestResolveEngineSettingEnvOverridesAll(t *testing.T) { +func TestResolveEngineSettingConfigTakesPriority(t *testing.T) { ctx := env.Set(t.Context(), engine.EnvVar, "terraform") b := &bundle.Bundle{Config: config.Root{Bundle: config.Bundle{Engine: engine.EngineDirect}}} result, err := ResolveEngineSetting(ctx, b) require.NoError(t, err) - assert.Equal(t, engine.EngineTerraform, result.Type) - assert.Equal(t, engine.EngineDirect, result.ConfigType) -} - -func TestResolveEngineSettingConfigOverridesDefault(t *testing.T) { - ctx := env.Set(t.Context(), engine.EnvVarDefault, "terraform") - b := &bundle.Bundle{Config: config.Root{Bundle: config.Bundle{Engine: engine.EngineDirect}}} - result, err := ResolveEngineSetting(ctx, b) - require.NoError(t, err) assert.Equal(t, engine.EngineDirect, result.Type) assert.Equal(t, engine.EngineDirect, result.ConfigType) } -func TestResolveEngineSettingDefaultUsedWhenNothingElseSet(t *testing.T) { - ctx := env.Set(t.Context(), engine.EnvVarDefault, "direct") +func TestResolveEngineSettingEnvVarUsedWhenNoConfig(t *testing.T) { + ctx := env.Set(t.Context(), engine.EnvVar, "direct") b := &bundle.Bundle{Config: config.Root{}} result, err := ResolveEngineSetting(ctx, b) require.NoError(t, err) assert.Equal(t, engine.EngineDirect, result.Type) - assert.Contains(t, result.Source, engine.EnvVarDefault) + assert.Contains(t, result.Source, engine.EnvVar) } func TestResolveEngineSettingNothingSet(t *testing.T) { @@ -52,9 +43,10 @@ func TestResolveEngineSettingInvalidEnvVar(t *testing.T) { assert.Error(t, err) } -func TestResolveEngineSettingInvalidDefaultEnvVar(t *testing.T) { - ctx := env.Set(t.Context(), engine.EnvVarDefault, "invalid") - b := &bundle.Bundle{Config: config.Root{}} - _, err := ResolveEngineSetting(ctx, b) - assert.Error(t, err) +func TestResolveEngineSettingInvalidEnvVarIgnoredWhenConfigSet(t *testing.T) { + ctx := env.Set(t.Context(), engine.EnvVar, "invalid") + b := &bundle.Bundle{Config: config.Root{Bundle: config.Bundle{Engine: engine.EngineDirect}}} + result, err := ResolveEngineSetting(ctx, b) + require.NoError(t, err) + assert.Equal(t, engine.EngineDirect, result.Type) } From db0d72c2b1d3a2968c2139ec273128cbc968887d Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 18 Mar 2026 12:41:36 +0100 Subject: [PATCH 5/6] update annotation --- bundle/internal/schema/annotations.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundle/internal/schema/annotations.yml b/bundle/internal/schema/annotations.yml index 97b17eb8a7..5d90fbebba 100644 --- a/bundle/internal/schema/annotations.yml +++ b/bundle/internal/schema/annotations.yml @@ -44,7 +44,7 @@ github.com/databricks/cli/bundle/config.Bundle: The definition of the bundle deployment. For supported attributes see [\_](/dev-tools/bundles/deployment-modes.md). "engine": "description": |- - The deployment engine to use. Valid values are `terraform` and `direct`. Can be overridden with the `DATABRICKS_BUNDLE_ENGINE` environment variable. + The deployment engine to use. Valid values are `terraform` and `direct`. Takes priority over `DATABRICKS_BUNDLE_ENGINE` environment variable. Default is "terraform". "git": "description": |- The Git version control details that are associated with your bundle. From 709267d65303a8829fa0ba3ac075b6f74714e476 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 18 Mar 2026 12:43:24 +0100 Subject: [PATCH 6/6] update jsonschema --- bundle/schema/jsonschema.json | 2 +- bundle/schema/jsonschema_for_docs.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json index 79090e5be5..e398ecf2b3 100644 --- a/bundle/schema/jsonschema.json +++ b/bundle/schema/jsonschema.json @@ -2159,7 +2159,7 @@ "markdownDescription": "The definition of the bundle deployment. For supported attributes see [link](https://docs.databricks.com/dev-tools/bundles/deployment-modes.html)." }, "engine": { - "description": "The deployment engine to use. Valid values are `terraform` and `direct`. Can be overridden with the `DATABRICKS_BUNDLE_ENGINE` environment variable.", + "description": "The deployment engine to use. Valid values are `terraform` and `direct`. Takes priority over `DATABRICKS_BUNDLE_ENGINE` environment variable. Default is \"terraform\".", "$ref": "#/$defs/github.com/databricks/cli/bundle/config/engine.EngineType" }, "git": { diff --git a/bundle/schema/jsonschema_for_docs.json b/bundle/schema/jsonschema_for_docs.json index 4ce01550cd..10a58f37b0 100644 --- a/bundle/schema/jsonschema_for_docs.json +++ b/bundle/schema/jsonschema_for_docs.json @@ -2151,7 +2151,7 @@ "x-since-version": "v0.229.0" }, "engine": { - "description": "The deployment engine to use. Valid values are `terraform` and `direct`. Can be overridden with the `DATABRICKS_BUNDLE_ENGINE` environment variable.", + "description": "The deployment engine to use. Valid values are `terraform` and `direct`. Takes priority over `DATABRICKS_BUNDLE_ENGINE` environment variable. Default is \"terraform\".", "$ref": "#/$defs/github.com/databricks/cli/bundle/config/engine.EngineType" }, "git": {