diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 491321a48c..30be1b7884 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -6,6 +6,7 @@ ### CLI * Skip non-exportable objects (e.g., `MLFLOW_EXPERIMENT`) during `workspace export-dir` instead of failing ([#4081](https://github.com/databricks/cli/issues/4081)) +* Allow domain_friendly_name to be used in name_prefix in development mode ([#4173](https://github.com/databricks/cli/pull/4173)) ### Bundles diff --git a/bundle/config/mutator/resourcemutator/validate_target_mode.go b/bundle/config/mutator/resourcemutator/validate_target_mode.go index ed8a6b796f..190c60c9b9 100644 --- a/bundle/config/mutator/resourcemutator/validate_target_mode.go +++ b/bundle/config/mutator/resourcemutator/validate_target_mode.go @@ -69,7 +69,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 != "" && !namePrefixContainsUserIdentifier(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 @@ -83,6 +83,21 @@ func validateDevelopmentMode(b *bundle.Bundle) diag.Diagnostics { return diags } +// namePrefixContainsUserIdentifier checks if the name prefix contains any user identifier +// (username, short name, or domain friendly name) to ensure uniqueness. +func namePrefixContainsUserIdentifier(prefix string, u *config.User) bool { + if strings.Contains(prefix, u.UserName) { + return true + } + if strings.Contains(prefix, u.ShortName) { + return true + } + if u.DomainFriendlyName != "" && strings.Contains(prefix, u.DomainFriendlyName) { + return true + } + return false +} + // findNonUserPath finds the first workspace path such as root_path that doesn't // contain the current username or current user's shortname. func findNonUserPath(b *bundle.Bundle) string { diff --git a/bundle/config/mutator/resourcemutator/validate_target_mode_test.go b/bundle/config/mutator/resourcemutator/validate_target_mode_test.go index 13ac277fba..f65d585954 100644 --- a/bundle/config/mutator/resourcemutator/validate_target_mode_test.go +++ b/bundle/config/mutator/resourcemutator/validate_target_mode_test.go @@ -192,4 +192,23 @@ func TestValidateDevelopmentMode(t *testing.T) { b.Config.Workspace.ResourcePath = "/Users/lennart@company.com/.bundle/x/y/resources" diags = validateDevelopmentMode(b) require.NoError(t, diags.Error()) + + // Test with a bundle that has a prefix containing the domain_friendly_name + b = mockBundle(config.Development) + b.Config.Workspace.CurrentUser.DomainFriendlyName = "lennartfriendly" + b.Config.Presets.NamePrefix = "[dev-lennartfriendly]" + diags = validateDevelopmentMode(b) + require.NoError(t, diags.Error()) + + // Test with a bundle that has a prefix containing the short_name + b = mockBundle(config.Development) + b.Config.Presets.NamePrefix = "[dev-lennart]" + diags = validateDevelopmentMode(b) + require.NoError(t, diags.Error()) + + // Test with a bundle that has a prefix containing the username + b = mockBundle(config.Development) + b.Config.Presets.NamePrefix = "[dev-lennart@company.com]" + diags = validateDevelopmentMode(b) + require.NoError(t, diags.Error()) }