From 02548702d8c03ff3d3c57fe2bb74a9a7b87e1b84 Mon Sep 17 00:00:00 2001 From: Jan Rose Date: Thu, 7 May 2026 16:05:37 +0200 Subject: [PATCH 1/4] Use ResourceDescription in validate_direct_only_resources Drop the local directOnlyResource struct (whose field names misnamed SingularTitle/SingularName as pluralName/singularName) and the per-type getResources closures. Iterate AllResources() and key off PluralName instead, reading SingularTitle/SingularName from the canonical ResourceDescription. Add a unit test covering direct/terraform engines and each direct-only resource type. Co-authored-by: Isaac --- .../mutator/validate_direct_only_resources.go | 79 ++++--------- .../validate_direct_only_resources_test.go | 110 ++++++++++++++++++ 2 files changed, 131 insertions(+), 58 deletions(-) create mode 100644 bundle/config/mutator/validate_direct_only_resources_test.go diff --git a/bundle/config/mutator/validate_direct_only_resources.go b/bundle/config/mutator/validate_direct_only_resources.go index 5717497205..a9b53c7098 100644 --- a/bundle/config/mutator/validate_direct_only_resources.go +++ b/bundle/config/mutator/validate_direct_only_resources.go @@ -9,51 +9,12 @@ import ( "github.com/databricks/cli/libs/diag" ) -type directOnlyResource struct { - resourceType string - pluralName string - singularName string - getResources func(*bundle.Bundle) map[string]any -} - -// Resources that are only supported in direct deployment mode -var directOnlyResources = []directOnlyResource{ - { - resourceType: "catalogs", - pluralName: "Catalog", - singularName: "catalog", - getResources: func(b *bundle.Bundle) map[string]any { - result := make(map[string]any) - for k, v := range b.Config.Resources.Catalogs { - result[k] = v - } - return result - }, - }, - { - resourceType: "external_locations", - pluralName: "External Location", - singularName: "external location", - getResources: func(b *bundle.Bundle) map[string]any { - result := make(map[string]any) - for k, v := range b.Config.Resources.ExternalLocations { - result[k] = v - } - return result - }, - }, - { - resourceType: "vector_search_endpoints", - pluralName: "Vector Search Endpoint", - singularName: "vector search endpoint", - getResources: func(b *bundle.Bundle) map[string]any { - result := make(map[string]any) - for k, v := range b.Config.Resources.VectorSearchEndpoints { - result[k] = v - } - return result - }, - }, +// directOnlyResourceTypes lists resources only supported in direct deployment mode. +// Keys are PluralName values from resources.ResourceDescription. +var directOnlyResourceTypes = map[string]bool{ + "catalogs": true, + "external_locations": true, + "vector_search_endpoints": true, } type validateDirectOnlyResources struct { @@ -76,20 +37,22 @@ func (m *validateDirectOnlyResources) Apply(ctx context.Context, b *bundle.Bundl } var diags diag.Diagnostics - - for _, resource := range directOnlyResources { - resourceMap := resource.getResources(b) - if len(resourceMap) > 0 { - diags = diags.Append(diag.Diagnostic{ - Severity: diag.Error, - Summary: resource.pluralName + " resources are only supported with direct deployment mode", - Detail: fmt.Sprintf("%s resources require direct deployment mode. "+ - "Please set the DATABRICKS_BUNDLE_ENGINE environment variable to 'direct' to use %s resources.\n"+ - "Learn more at https://docs.databricks.com/dev-tools/bundles/direct", - resource.pluralName, resource.singularName), - Locations: b.Config.GetLocations("resources." + resource.resourceType), - }) + for _, group := range b.Config.Resources.AllResources() { + if !directOnlyResourceTypes[group.Description.PluralName] { + continue + } + if len(group.Resources) == 0 { + continue } + diags = diags.Append(diag.Diagnostic{ + Severity: diag.Error, + Summary: group.Description.SingularTitle + " resources are only supported with direct deployment mode", + Detail: fmt.Sprintf("%s resources require direct deployment mode. "+ + "Please set the DATABRICKS_BUNDLE_ENGINE environment variable to 'direct' to use %s resources.\n"+ + "Learn more at https://docs.databricks.com/dev-tools/bundles/direct", + group.Description.SingularTitle, group.Description.SingularName), + Locations: b.Config.GetLocations("resources." + group.Description.PluralName), + }) } return diags diff --git a/bundle/config/mutator/validate_direct_only_resources_test.go b/bundle/config/mutator/validate_direct_only_resources_test.go new file mode 100644 index 0000000000..dbc184c752 --- /dev/null +++ b/bundle/config/mutator/validate_direct_only_resources_test.go @@ -0,0 +1,110 @@ +package mutator_test + +import ( + "testing" + + "github.com/databricks/cli/bundle" + "github.com/databricks/cli/bundle/config" + "github.com/databricks/cli/bundle/config/engine" + "github.com/databricks/cli/bundle/config/mutator" + "github.com/databricks/cli/bundle/config/resources" + "github.com/stretchr/testify/assert" +) + +func TestValidateDirectOnlyResourcesDirectEngineReturnsNil(t *testing.T) { + b := &bundle.Bundle{ + Config: config.Root{ + Resources: config.Resources{ + Catalogs: map[string]*resources.Catalog{ + "my_catalog": {}, + }, + }, + }, + } + + diags := bundle.Apply(t.Context(), b, mutator.ValidateDirectOnlyResources(engine.EngineDirect)) + assert.Empty(t, diags) +} + +func TestValidateDirectOnlyResourcesTerraformEngineNoDirectOnlyReturnsNil(t *testing.T) { + b := &bundle.Bundle{ + Config: config.Root{ + Resources: config.Resources{ + Jobs: map[string]*resources.Job{ + "my_job": {}, + }, + }, + }, + } + + diags := bundle.Apply(t.Context(), b, mutator.ValidateDirectOnlyResources(engine.EngineTerraform)) + assert.Empty(t, diags) +} + +func TestValidateDirectOnlyResourcesTerraformEngineDirectOnlyEmitsError(t *testing.T) { + cases := []struct { + name string + bundle *bundle.Bundle + expectedSummary string + expectedDetail string + }{ + { + name: "catalogs", + bundle: &bundle.Bundle{ + Config: config.Root{ + Resources: config.Resources{ + Catalogs: map[string]*resources.Catalog{ + "my_catalog": {}, + }, + }, + }, + }, + expectedSummary: "Catalog resources are only supported with direct deployment mode", + expectedDetail: "Catalog resources require direct deployment mode. " + + "Please set the DATABRICKS_BUNDLE_ENGINE environment variable to 'direct' to use catalog resources.\n" + + "Learn more at https://docs.databricks.com/dev-tools/bundles/direct", + }, + { + name: "external_locations", + bundle: &bundle.Bundle{ + Config: config.Root{ + Resources: config.Resources{ + ExternalLocations: map[string]*resources.ExternalLocation{ + "my_location": {}, + }, + }, + }, + }, + expectedSummary: "External Location resources are only supported with direct deployment mode", + expectedDetail: "External Location resources require direct deployment mode. " + + "Please set the DATABRICKS_BUNDLE_ENGINE environment variable to 'direct' to use external_location resources.\n" + + "Learn more at https://docs.databricks.com/dev-tools/bundles/direct", + }, + { + name: "vector_search_endpoints", + bundle: &bundle.Bundle{ + Config: config.Root{ + Resources: config.Resources{ + VectorSearchEndpoints: map[string]*resources.VectorSearchEndpoint{ + "my_endpoint": {}, + }, + }, + }, + }, + expectedSummary: "Vector Search Endpoint resources are only supported with direct deployment mode", + expectedDetail: "Vector Search Endpoint resources require direct deployment mode. " + + "Please set the DATABRICKS_BUNDLE_ENGINE environment variable to 'direct' to use vector_search_endpoint resources.\n" + + "Learn more at https://docs.databricks.com/dev-tools/bundles/direct", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + diags := bundle.Apply(t.Context(), tc.bundle, mutator.ValidateDirectOnlyResources(engine.EngineTerraform)) + if assert.Len(t, diags, 1) { + assert.Equal(t, tc.expectedSummary, diags[0].Summary) + assert.Equal(t, tc.expectedDetail, diags[0].Detail) + } + }) + } +} From 62d4ae81d61322dbec9993be3ca3da89fdae98e7 Mon Sep 17 00:00:00 2001 From: Jan Rose Date: Thu, 7 May 2026 16:05:53 +0200 Subject: [PATCH 2/4] Collapse per-type if-chains in approvalForDeploy/Destroy Replace the eight (deploy) and seven (destroy) near-identical 'if len(...) != 0 { LogString(message); for _ { Log(action) } }' blocks with a table-driven helper, logApprovalGroups, that takes a slice of {group, message, skipChildren, trailingGap} entries. deploy collapses the eight-clause len()==0 early-return to total==0 returned from the helper. The schema child-resource skip and the destroy trailing blank lines are preserved via the per-group flags. The outer "all deletes" preamble in destroy stays as-is because it is structurally different (it skips children and has no trailing banner per group). Co-authored-by: Isaac --- bundle/phases/approval.go | 41 +++++++++++++++ bundle/phases/deploy.go | 102 ++++++-------------------------------- bundle/phases/destroy.go | 81 +++++------------------------- 3 files changed, 68 insertions(+), 156 deletions(-) create mode 100644 bundle/phases/approval.go diff --git a/bundle/phases/approval.go b/bundle/phases/approval.go new file mode 100644 index 0000000000..bea133b840 --- /dev/null +++ b/bundle/phases/approval.go @@ -0,0 +1,41 @@ +package phases + +import ( + "context" + + "github.com/databricks/cli/bundle/deployplan" + "github.com/databricks/cli/libs/cmdio" +) + +// approvalGroup describes one resource type that needs explicit user consent +// before a destructive action is applied. +type approvalGroup struct { + group string // matches config.GetResourceTypeFromKey, e.g. "schemas" + message string // banner shown above the action list + skipChildren bool // skip actions where IsChildResource() is true + trailingGap bool // print an empty line after the block (destroy only) +} + +// logApprovalGroups filters actions per group and prints non-empty groups. +// Returns the total number of matched actions across all groups. +func logApprovalGroups(ctx context.Context, actions []deployplan.Action, groups []approvalGroup, types ...deployplan.ActionType) int { + total := 0 + for _, g := range groups { + matched := filterGroup(actions, g.group, types...) + if len(matched) == 0 { + continue + } + total += len(matched) + cmdio.LogString(ctx, g.message) + for _, a := range matched { + if g.skipChildren && a.IsChildResource() { + continue + } + cmdio.Log(ctx, a) + } + if g.trailingGap { + cmdio.LogString(ctx, "") + } + } + return total +} diff --git a/bundle/phases/deploy.go b/bundle/phases/deploy.go index 38389b9adb..dc13135c28 100644 --- a/bundle/phases/deploy.go +++ b/bundle/phases/deploy.go @@ -26,6 +26,17 @@ import ( "github.com/databricks/cli/libs/sync" ) +var deployApprovalGroups = []approvalGroup{ + {group: "schemas", message: deleteOrRecreateSchemaMessage, skipChildren: true}, + {group: "pipelines", message: deleteOrRecreatePipelineMessage}, + {group: "volumes", message: deleteOrRecreateVolumeMessage}, + {group: "dashboards", message: deleteOrRecreateDashboardMessage}, + {group: "database_instances", message: deleteOrRecreateDatabaseInstanceMessage}, + {group: "synced_database_tables", message: deleteOrRecreateSyncedDatabaseTableMessage}, + {group: "postgres_projects", message: deleteOrRecreatePostgresProjectMessage}, + {group: "postgres_branches", message: deleteOrRecreatePostgresBranchMessage}, +} + func approvalForDeploy(ctx context.Context, b *bundle.Bundle, plan *deployplan.Plan) (bool, error) { actions := plan.GetActions() @@ -34,90 +45,12 @@ func approvalForDeploy(ctx context.Context, b *bundle.Bundle, plan *deployplan.P return false, err } - types := []deployplan.ActionType{deployplan.Recreate, deployplan.Delete} - schemaActions := filterGroup(actions, "schemas", types...) - pipelineActions := filterGroup(actions, "pipelines", types...) - volumeActions := filterGroup(actions, "volumes", types...) - dashboardActions := filterGroup(actions, "dashboards", types...) - databaseInstanceActions := filterGroup(actions, "database_instances", types...) - syncedDatabaseTableActions := filterGroup(actions, "synced_database_tables", types...) - postgresProjectActions := filterGroup(actions, "postgres_projects", types...) - postgresBranchActions := filterGroup(actions, "postgres_branches", types...) - - // We don't need to display any prompts in this case. - if len(schemaActions) == 0 && len(pipelineActions) == 0 && len(volumeActions) == 0 && len(dashboardActions) == 0 && - len(databaseInstanceActions) == 0 && len(syncedDatabaseTableActions) == 0 && - len(postgresProjectActions) == 0 && len(postgresBranchActions) == 0 { + total := logApprovalGroups(ctx, actions, deployApprovalGroups, deployplan.Recreate, deployplan.Delete) + if total == 0 { + // No destructive actions in any tracked group: skip the prompt. return true, nil } - // One or more UC schema resources will be deleted or recreated. - if len(schemaActions) != 0 { - cmdio.LogString(ctx, deleteOrRecreateSchemaMessage) - for _, action := range schemaActions { - if action.IsChildResource() { - continue - } - cmdio.Log(ctx, action) - } - } - - // One or more pipelines is being recreated. - if len(pipelineActions) != 0 { - cmdio.LogString(ctx, deleteOrRecreatePipelineMessage) - for _, action := range pipelineActions { - cmdio.Log(ctx, action) - } - } - - // One or more volumes is being recreated. - if len(volumeActions) != 0 { - cmdio.LogString(ctx, deleteOrRecreateVolumeMessage) - for _, action := range volumeActions { - cmdio.Log(ctx, action) - } - } - - // One or more dashboards is being recreated. - if len(dashboardActions) != 0 { - cmdio.LogString(ctx, deleteOrRecreateDashboardMessage) - for _, action := range dashboardActions { - cmdio.Log(ctx, action) - } - } - - // One or more database instances is being deleted or recreated. - if len(databaseInstanceActions) != 0 { - cmdio.LogString(ctx, deleteOrRecreateDatabaseInstanceMessage) - for _, action := range databaseInstanceActions { - cmdio.Log(ctx, action) - } - } - - // One or more synced database tables is being deleted or recreated. - if len(syncedDatabaseTableActions) != 0 { - cmdio.LogString(ctx, deleteOrRecreateSyncedDatabaseTableMessage) - for _, action := range syncedDatabaseTableActions { - cmdio.Log(ctx, action) - } - } - - // One or more Lakebase projects is being deleted or recreated. - if len(postgresProjectActions) != 0 { - cmdio.LogString(ctx, deleteOrRecreatePostgresProjectMessage) - for _, action := range postgresProjectActions { - cmdio.Log(ctx, action) - } - } - - // One or more Lakebase branches is being deleted or recreated. - if len(postgresBranchActions) != 0 { - cmdio.LogString(ctx, deleteOrRecreatePostgresBranchMessage) - for _, action := range postgresBranchActions { - cmdio.Log(ctx, action) - } - } - if b.AutoApprove { return true, nil } @@ -127,12 +60,7 @@ func approvalForDeploy(ctx context.Context, b *bundle.Bundle, plan *deployplan.P } cmdio.LogString(ctx, "") - approved, err := cmdio.AskYesOrNo(ctx, "Would you like to proceed?") - if err != nil { - return false, err - } - - return approved, nil + return cmdio.AskYesOrNo(ctx, "Would you like to proceed?") } func deployCore(ctx context.Context, b *bundle.Bundle, plan *deployplan.Plan, targetEngine engine.EngineType) { diff --git a/bundle/phases/destroy.go b/bundle/phases/destroy.go index 4abc6140e4..a437e6939d 100644 --- a/bundle/phases/destroy.go +++ b/bundle/phases/destroy.go @@ -32,6 +32,16 @@ func assertRootPathExists(ctx context.Context, b *bundle.Bundle) (bool, error) { return true, err } +var destroyApprovalGroups = []approvalGroup{ + {group: "schemas", message: deleteSchemaMessage, trailingGap: true}, + {group: "pipelines", message: deletePipelineMessage, trailingGap: true}, + {group: "volumes", message: deleteVolumeMessage, trailingGap: true}, + {group: "database_instances", message: deleteDatabaseInstanceMessage, trailingGap: true}, + {group: "synced_database_tables", message: deleteSyncedDatabaseTableMessage, trailingGap: true}, + {group: "postgres_projects", message: deletePostgresProjectMessage, trailingGap: true}, + {group: "postgres_branches", message: deletePostgresBranchMessage, trailingGap: true}, +} + func approvalForDestroy(ctx context.Context, b *bundle.Bundle, plan *deployplan.Plan) (bool, error) { deleteActions := plan.GetActions() @@ -51,69 +61,7 @@ func approvalForDestroy(ctx context.Context, b *bundle.Bundle, plan *deployplan. cmdio.LogString(ctx, "") } - schemaActions := filterGroup(deleteActions, "schemas", deployplan.Delete) - pipelineActions := filterGroup(deleteActions, "pipelines", deployplan.Delete) - volumeActions := filterGroup(deleteActions, "volumes", deployplan.Delete) - databaseInstanceActions := filterGroup(deleteActions, "database_instances", deployplan.Delete) - syncedDatabaseTableActions := filterGroup(deleteActions, "synced_database_tables", deployplan.Delete) - postgresProjectActions := filterGroup(deleteActions, "postgres_projects", deployplan.Delete) - postgresBranchActions := filterGroup(deleteActions, "postgres_branches", deployplan.Delete) - - if len(schemaActions) > 0 { - cmdio.LogString(ctx, deleteSchemaMessage) - for _, a := range schemaActions { - cmdio.Log(ctx, a) - } - cmdio.LogString(ctx, "") - } - - if len(pipelineActions) > 0 { - cmdio.LogString(ctx, deletePipelineMessage) - for _, a := range pipelineActions { - cmdio.Log(ctx, a) - } - cmdio.LogString(ctx, "") - } - - if len(volumeActions) > 0 { - cmdio.LogString(ctx, deleteVolumeMessage) - for _, a := range volumeActions { - cmdio.Log(ctx, a) - } - cmdio.LogString(ctx, "") - } - - if len(databaseInstanceActions) > 0 { - cmdio.LogString(ctx, deleteDatabaseInstanceMessage) - for _, a := range databaseInstanceActions { - cmdio.Log(ctx, a) - } - cmdio.LogString(ctx, "") - } - - if len(syncedDatabaseTableActions) > 0 { - cmdio.LogString(ctx, deleteSyncedDatabaseTableMessage) - for _, a := range syncedDatabaseTableActions { - cmdio.Log(ctx, a) - } - cmdio.LogString(ctx, "") - } - - if len(postgresProjectActions) > 0 { - cmdio.LogString(ctx, deletePostgresProjectMessage) - for _, a := range postgresProjectActions { - cmdio.Log(ctx, a) - } - cmdio.LogString(ctx, "") - } - - if len(postgresBranchActions) > 0 { - cmdio.LogString(ctx, deletePostgresBranchMessage) - for _, a := range postgresBranchActions { - cmdio.Log(ctx, a) - } - cmdio.LogString(ctx, "") - } + logApprovalGroups(ctx, deleteActions, destroyApprovalGroups, deployplan.Delete) cmdio.LogString(ctx, "All files and directories at the following location will be deleted: "+b.Config.Workspace.RootPath) cmdio.LogString(ctx, "") @@ -122,12 +70,7 @@ func approvalForDestroy(ctx context.Context, b *bundle.Bundle, plan *deployplan. return true, nil } - approved, err := cmdio.AskYesOrNo(ctx, "Would you like to proceed?") - if err != nil { - return false, err - } - - return approved, nil + return cmdio.AskYesOrNo(ctx, "Would you like to proceed?") } func destroyCore(ctx context.Context, b *bundle.Bundle, plan *deployplan.Plan, engine engine.EngineType) { From 6e6940d5d45c02594658dfd8a47644c7c0cbe1be Mon Sep 17 00:00:00 2001 From: Jan Rose Date: Fri, 8 May 2026 14:39:38 +0200 Subject: [PATCH 3/4] Compute direct-only resources from existing engine maps Replace the hardcoded directOnlyResourceTypes set with a check against dresources.SupportedResources and terraform.GroupToTerraformName: a resource type is direct-only if it appears in the former but not the latter. Removes the third source of truth for which resource types exist where. Co-authored-by: Isaac --- .../mutator/validate_direct_only_resources.go | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/bundle/config/mutator/validate_direct_only_resources.go b/bundle/config/mutator/validate_direct_only_resources.go index a9b53c7098..556b7b815a 100644 --- a/bundle/config/mutator/validate_direct_only_resources.go +++ b/bundle/config/mutator/validate_direct_only_resources.go @@ -6,17 +6,11 @@ import ( "github.com/databricks/cli/bundle" "github.com/databricks/cli/bundle/config/engine" + "github.com/databricks/cli/bundle/deploy/terraform" + "github.com/databricks/cli/bundle/direct/dresources" "github.com/databricks/cli/libs/diag" ) -// directOnlyResourceTypes lists resources only supported in direct deployment mode. -// Keys are PluralName values from resources.ResourceDescription. -var directOnlyResourceTypes = map[string]bool{ - "catalogs": true, - "external_locations": true, - "vector_search_endpoints": true, -} - type validateDirectOnlyResources struct { engine engine.EngineType } @@ -31,6 +25,15 @@ func (m *validateDirectOnlyResources) Name() string { return "ValidateDirectOnlyResources" } +// isDirectOnly reports whether a resource type (by PluralName) is supported only +// by the direct engine — present in dresources.SupportedResources but absent +// from terraform.GroupToTerraformName. +func isDirectOnly(pluralName string) bool { + _, hasDirect := dresources.SupportedResources[pluralName] + _, hasTerraform := terraform.GroupToTerraformName[pluralName] + return hasDirect && !hasTerraform +} + func (m *validateDirectOnlyResources) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics { if m.engine.IsDirect() { return nil @@ -38,10 +41,10 @@ func (m *validateDirectOnlyResources) Apply(ctx context.Context, b *bundle.Bundl var diags diag.Diagnostics for _, group := range b.Config.Resources.AllResources() { - if !directOnlyResourceTypes[group.Description.PluralName] { + if len(group.Resources) == 0 { continue } - if len(group.Resources) == 0 { + if !isDirectOnly(group.Description.PluralName) { continue } diags = diags.Append(diag.Diagnostic{ From c3bef3029146b91ce093146fb05b18f2a7525d72 Mon Sep 17 00:00:00 2001 From: Jan Rose Date: Fri, 8 May 2026 14:39:50 +0200 Subject: [PATCH 4/4] Pass trailingNewline as a parameter to logApprovalGroups Drop the per-group trailingGap field on approvalGroup (it was always true for destroy and never set for deploy) and pass a single bool parameter to logApprovalGroups instead. Also rename the concept from "gap" to "newline" since that's what cmdio.LogString(ctx, "") prints. Co-authored-by: Isaac --- bundle/phases/approval.go | 6 +++--- bundle/phases/deploy.go | 2 +- bundle/phases/destroy.go | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bundle/phases/approval.go b/bundle/phases/approval.go index bea133b840..fdbcd8ecea 100644 --- a/bundle/phases/approval.go +++ b/bundle/phases/approval.go @@ -13,12 +13,12 @@ type approvalGroup struct { group string // matches config.GetResourceTypeFromKey, e.g. "schemas" message string // banner shown above the action list skipChildren bool // skip actions where IsChildResource() is true - trailingGap bool // print an empty line after the block (destroy only) } // logApprovalGroups filters actions per group and prints non-empty groups. +// If trailingNewline is true, an empty line is printed after each non-empty group. // Returns the total number of matched actions across all groups. -func logApprovalGroups(ctx context.Context, actions []deployplan.Action, groups []approvalGroup, types ...deployplan.ActionType) int { +func logApprovalGroups(ctx context.Context, actions []deployplan.Action, groups []approvalGroup, trailingNewline bool, types ...deployplan.ActionType) int { total := 0 for _, g := range groups { matched := filterGroup(actions, g.group, types...) @@ -33,7 +33,7 @@ func logApprovalGroups(ctx context.Context, actions []deployplan.Action, groups } cmdio.Log(ctx, a) } - if g.trailingGap { + if trailingNewline { cmdio.LogString(ctx, "") } } diff --git a/bundle/phases/deploy.go b/bundle/phases/deploy.go index dc13135c28..b4d70ede5a 100644 --- a/bundle/phases/deploy.go +++ b/bundle/phases/deploy.go @@ -45,7 +45,7 @@ func approvalForDeploy(ctx context.Context, b *bundle.Bundle, plan *deployplan.P return false, err } - total := logApprovalGroups(ctx, actions, deployApprovalGroups, deployplan.Recreate, deployplan.Delete) + total := logApprovalGroups(ctx, actions, deployApprovalGroups, false, deployplan.Recreate, deployplan.Delete) if total == 0 { // No destructive actions in any tracked group: skip the prompt. return true, nil diff --git a/bundle/phases/destroy.go b/bundle/phases/destroy.go index a437e6939d..91640ac6ca 100644 --- a/bundle/phases/destroy.go +++ b/bundle/phases/destroy.go @@ -33,13 +33,13 @@ func assertRootPathExists(ctx context.Context, b *bundle.Bundle) (bool, error) { } var destroyApprovalGroups = []approvalGroup{ - {group: "schemas", message: deleteSchemaMessage, trailingGap: true}, - {group: "pipelines", message: deletePipelineMessage, trailingGap: true}, - {group: "volumes", message: deleteVolumeMessage, trailingGap: true}, - {group: "database_instances", message: deleteDatabaseInstanceMessage, trailingGap: true}, - {group: "synced_database_tables", message: deleteSyncedDatabaseTableMessage, trailingGap: true}, - {group: "postgres_projects", message: deletePostgresProjectMessage, trailingGap: true}, - {group: "postgres_branches", message: deletePostgresBranchMessage, trailingGap: true}, + {group: "schemas", message: deleteSchemaMessage}, + {group: "pipelines", message: deletePipelineMessage}, + {group: "volumes", message: deleteVolumeMessage}, + {group: "database_instances", message: deleteDatabaseInstanceMessage}, + {group: "synced_database_tables", message: deleteSyncedDatabaseTableMessage}, + {group: "postgres_projects", message: deletePostgresProjectMessage}, + {group: "postgres_branches", message: deletePostgresBranchMessage}, } func approvalForDestroy(ctx context.Context, b *bundle.Bundle, plan *deployplan.Plan) (bool, error) { @@ -61,7 +61,7 @@ func approvalForDestroy(ctx context.Context, b *bundle.Bundle, plan *deployplan. cmdio.LogString(ctx, "") } - logApprovalGroups(ctx, deleteActions, destroyApprovalGroups, deployplan.Delete) + logApprovalGroups(ctx, deleteActions, destroyApprovalGroups, true, deployplan.Delete) cmdio.LogString(ctx, "All files and directories at the following location will be deleted: "+b.Config.Workspace.RootPath) cmdio.LogString(ctx, "")