From be2d802d13064477fb6b8c8159a048de06ae7bb5 Mon Sep 17 00:00:00 2001 From: Shreyas Goenka Date: Mon, 14 Oct 2024 16:43:58 +0200 Subject: [PATCH] Skip prefixes for schema names when catalog is already namespaced to current user --- bundle/config/mutator/apply_presets.go | 9 +++++ bundle/config/mutator/apply_presets_test.go | 42 ++++++++++++++++++++ bundle/config/mutator/process_target_mode.go | 6 ++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/bundle/config/mutator/apply_presets.go b/bundle/config/mutator/apply_presets.go index 1fd49206..4b677a5a 100644 --- a/bundle/config/mutator/apply_presets.go +++ b/bundle/config/mutator/apply_presets.go @@ -11,6 +11,7 @@ import ( "github.com/databricks/cli/bundle/config" "github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/dyn" + "github.com/databricks/cli/libs/log" "github.com/databricks/cli/libs/textutil" "github.com/databricks/databricks-sdk-go/service/catalog" "github.com/databricks/databricks-sdk-go/service/jobs" @@ -188,6 +189,14 @@ func (m *applyPresets) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnos diags = diags.Extend(diag.Errorf("schema %s is not defined", key)) continue } + + // If the catalog is already namespaced to the current user, we don't need + // to prefix the schema name since it already falls under the user's namespace. + if containsUserIdentity(s.CatalogName, b.Config.Workspace.CurrentUser) { + log.Debugf(ctx, "Skipping schema %s since catalog %s already contains the user's identity", s.Name, s.CatalogName) + continue + } + s.Name = normalizePrefix(prefix) + s.Name // HTTP API for schemas doesn't yet support tags. It's only supported in // the Databricks UI and via the SQL API. diff --git a/bundle/config/mutator/apply_presets_test.go b/bundle/config/mutator/apply_presets_test.go index 24295da4..43f82a5a 100644 --- a/bundle/config/mutator/apply_presets_test.go +++ b/bundle/config/mutator/apply_presets_test.go @@ -9,6 +9,7 @@ import ( "github.com/databricks/cli/bundle/config/mutator" "github.com/databricks/cli/bundle/config/resources" "github.com/databricks/databricks-sdk-go/service/catalog" + "github.com/databricks/databricks-sdk-go/service/iam" "github.com/databricks/databricks-sdk-go/service/jobs" "github.com/stretchr/testify/require" ) @@ -96,12 +97,53 @@ func TestApplyPresetsPrefixForUcSchema(t *testing.T) { }, want: "schema1", }, + { + name: "skip prefix because catalog contains short name", + prefix: "[prefix]", + schema: &resources.Schema{ + CreateSchema: &catalog.CreateSchema{ + Name: "schema1", + CatalogName: "dev_john_smith_test_catalog", + }, + }, + want: "schema1", + }, + { + name: "skip prefix because catalog contains email", + prefix: "[prefix]", + schema: &resources.Schema{ + CreateSchema: &catalog.CreateSchema{ + Name: "schema1", + CatalogName: "dev_john.smith@databricks.com_test_catalog", + }, + }, + want: "schema1", + }, + { + name: "add prefix because catalog is not namespaced to user", + prefix: "[prefix]", + schema: &resources.Schema{ + CreateSchema: &catalog.CreateSchema{ + Name: "schema1", + CatalogName: "test_catalog", + }, + }, + want: "prefix_schema1", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { b := &bundle.Bundle{ Config: config.Root{ + Workspace: config.Workspace{ + CurrentUser: &config.User{ + ShortName: "john_smith", + User: &iam.User{ + UserName: "john.smith@databricks.com", + }, + }, + }, Resources: config.Resources{ Schemas: map[string]*resources.Schema{ "schema1": tt.schema, diff --git a/bundle/config/mutator/process_target_mode.go b/bundle/config/mutator/process_target_mode.go index 44b53681..870afe9d 100644 --- a/bundle/config/mutator/process_target_mode.go +++ b/bundle/config/mutator/process_target_mode.go @@ -63,6 +63,10 @@ func transformDevelopmentMode(ctx context.Context, b *bundle.Bundle) { } } +func containsUserIdentity(s string, u *config.User) bool { + return strings.Contains(s, u.ShortName) || strings.Contains(s, u.UserName) +} + func validateDevelopmentMode(b *bundle.Bundle) diag.Diagnostics { var diags diag.Diagnostics p := b.Config.Presets @@ -92,7 +96,7 @@ func validateDevelopmentMode(b *bundle.Bundle) diag.Diagnostics { diags = diags.Extend(diag.Errorf("%s must start with '~/' or contain the current username to ensure uniqueness when using 'mode: development'", path)) } } - if p.NamePrefix != "" && !strings.Contains(p.NamePrefix, u.ShortName) && !strings.Contains(p.NamePrefix, u.UserName) { + if p.NamePrefix != "" && !containsUserIdentity(p.NamePrefix, u) { // Resources such as pipelines require a unique name, e.g. '[dev steve] my_pipeline'. // For this reason we require the name prefix to contain the current username; // it's a pitfall for users if they don't include it and later find out that