From 3a65fe4d3980534db5b46dd39a9a85e0ae8d6468 Mon Sep 17 00:00:00 2001 From: Shreyas Goenka Date: Wed, 14 Oct 2026 11:58:09 +0000 Subject: [PATCH] Let deployment history configuration override the environment --- bundle/config/experimental.go | 3 ++- bundle/env/dms.go | 9 +++++---- bundle/env/dms_test.go | 32 +++++++++++++++++++++++--------- cmd/bundle/utils/process.go | 5 ++++- cmd/bundle/utils/process_test.go | 4 ++-- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/bundle/config/experimental.go b/bundle/config/experimental.go index 03cd2ba30d4..6fd5511b79b 100644 --- a/bundle/config/experimental.go +++ b/bundle/config/experimental.go @@ -56,7 +56,8 @@ type Experimental struct { // // Only for bundles with no deployed resources yet: DMS becomes the source of // truth for their state. - DeploymentHistory bool `json:"deployment_history,omitempty"` + // An explicit value takes priority over the environment setting. + DeploymentHistory *bool `json:"deployment_history,omitempty"` } type Python struct { diff --git a/bundle/env/dms.go b/bundle/env/dms.go index 2474b468da4..a92d9f09a07 100644 --- a/bundle/env/dms.go +++ b/bundle/env/dms.go @@ -8,11 +8,12 @@ import "context" const DeploymentHistoryVariable = "DATABRICKS_BUNDLE_DEPLOYMENT_HISTORY" // RecordsDeploymentHistory reports whether recording is on, from config or env var. Single predicate -// for all recording code paths, keeping them in sync. The env var only counts as "true": anything +// for all recording code paths, keeping them in sync. Explicit config takes priority over the env var. +// The env var only counts as "true": anything // else - a typo like "TRUE" or "yes" - leaves recording off rather than silently enabling it. -func RecordsDeploymentHistory(ctx context.Context, configured bool) bool { - if configured { - return true +func RecordsDeploymentHistory(ctx context.Context, configured *bool) bool { + if configured != nil { + return *configured } value, _ := get(ctx, []string{DeploymentHistoryVariable}) return value == "true" diff --git a/bundle/env/dms_test.go b/bundle/env/dms_test.go index 469b7707e85..5bfad6df39a 100644 --- a/bundle/env/dms_test.go +++ b/bundle/env/dms_test.go @@ -22,20 +22,34 @@ func TestDeploymentHistoryEnv(t *testing.T) { {"yes", false}, } { ctx := env.Set(t.Context(), DeploymentHistoryVariable, tc.value) - assert.Equal(t, tc.want, RecordsDeploymentHistory(ctx, false), "value %q", tc.value) + assert.Equal(t, tc.want, RecordsDeploymentHistory(ctx, nil), "value %q", tc.value) } } func TestDeploymentHistoryEnvUnset(t *testing.T) { - assert.False(t, RecordsDeploymentHistory(t.Context(), false)) + assert.False(t, RecordsDeploymentHistory(t.Context(), nil)) } func TestRecordsDeploymentHistory(t *testing.T) { - // The bundle setting alone is enough, and so is the environment; the env var - // exists so the acceptance suite can record without touching every databricks.yml. - assert.True(t, RecordsDeploymentHistory(t.Context(), true)) - assert.False(t, RecordsDeploymentHistory(t.Context(), false)) - - ctx := env.Set(t.Context(), DeploymentHistoryVariable, "true") - assert.True(t, RecordsDeploymentHistory(ctx, false)) + for _, tc := range []struct { + name string + configured *bool + value string + want bool + }{ + {"config true env true", new(true), "true", true}, + {"config true env false", new(true), "false", true}, + {"config true env unset", new(true), "", true}, + {"config false env true", new(false), "true", false}, + {"config false env false", new(false), "false", false}, + {"config false env unset", new(false), "", false}, + {"config unset env true", nil, "true", true}, + {"config unset env false", nil, "false", false}, + {"config unset env unset", nil, "", false}, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := env.Set(t.Context(), DeploymentHistoryVariable, tc.value) + assert.Equal(t, tc.want, RecordsDeploymentHistory(ctx, tc.configured)) + }) + } } diff --git a/cmd/bundle/utils/process.go b/cmd/bundle/utils/process.go index cbc8cf93212..6ccb3367db7 100644 --- a/cmd/bundle/utils/process.go +++ b/cmd/bundle/utils/process.go @@ -693,7 +693,10 @@ Run "databricks bundle destroy" first, then deploy again with deployment history } func configuresDeploymentHistory(ctx context.Context, b *bundle.Bundle) bool { - configured := b.Config.Experimental != nil && b.Config.Experimental.DeploymentHistory + var configured *bool + if b.Config.Experimental != nil { + configured = b.Config.Experimental.DeploymentHistory + } return bundleenv.RecordsDeploymentHistory(ctx, configured) } diff --git a/cmd/bundle/utils/process_test.go b/cmd/bundle/utils/process_test.go index 080229889b6..b216f1102d2 100644 --- a/cmd/bundle/utils/process_test.go +++ b/cmd/bundle/utils/process_test.go @@ -14,14 +14,14 @@ import ( func TestResolveDeploymentHistory(t *testing.T) { b := &bundle.Bundle{Config: config.Root{ - Experimental: &config.Experimental{DeploymentHistory: true}, + Experimental: &config.Experimental{DeploymentHistory: new(true)}, }} newState := &statemgmt.StateDesc{} assert.True(t, resolveDeploymentHistory(t.Context(), b, newState)) assert.True(t, newState.IsDMS()) assert.False(t, resolveDeploymentHistory(t.Context(), b, &statemgmt.StateDesc{SourcePath: "resources.json"})) - b.Config.Experimental.DeploymentHistory = false + b.Config.Experimental.DeploymentHistory = new(false) assert.True(t, resolveDeploymentHistory(t.Context(), b, &statemgmt.StateDesc{ SourcePath: "resources.json", Features: map[string]struct{}{dstate.FeatureDeploymentHistory: {}},