Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bundle/config/mutator/populate_current_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (m *populateCurrentUser) Apply(ctx context.Context, b *bundle.Bundle) diag.
}

b.Config.Workspace.CurrentUser = &config.User{
ShortName: auth.GetShortUserName(me.UserName),
ShortName: auth.GetShortUserName(me),
User: me,
}

Expand Down
2 changes: 1 addition & 1 deletion internal/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func TestAccBundleInitHelpers(t *testing.T) {
}{
{
funcName: "{{short_name}}",
expected: auth.GetShortUserName(me.UserName),
expected: auth.GetShortUserName(me),
},
{
funcName: "{{user_name}}",
Expand Down
13 changes: 11 additions & 2 deletions libs/auth/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@ import (
"strings"

"github.com/databricks/cli/libs/textutil"
"github.com/databricks/databricks-sdk-go/service/iam"
)

// Get a short-form username, based on the user's primary email address.
// We leave the full range of unicode letters in tact, but remove all "special" characters,
// including dots, which are not supported in e.g. experiment names.
func GetShortUserName(emailAddress string) string {
local, _, _ := strings.Cut(emailAddress, "@")
func GetShortUserName(user *iam.User) string {
var name string
if IsServicePrincipal(user.UserName) {
// Try use the display name of the principal (if it has one)
name = user.DisplayName
}
if name == "" {
name = user.UserName
}
local, _, _ := strings.Cut(name, "@")
Comment thread
lennartkats-db marked this conversation as resolved.
return textutil.NormalizeString(local)
}
71 changes: 56 additions & 15 deletions libs/auth/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,111 @@ package auth
import (
"testing"

"github.com/databricks/databricks-sdk-go/service/iam"
"github.com/stretchr/testify/assert"
)

func TestGetShortUserName(t *testing.T) {
tests := []struct {
name string
email string
user *iam.User
expected string
}{
{
email: "test.user.1234@example.com",
user: &iam.User{
UserName: "test.user.1234@example.com",
},
expected: "test_user_1234",
},
{
email: "tést.üser@example.com",
user: &iam.User{
UserName: "tést.üser@example.com",
},
expected: "tést_üser",
},
{
email: "test$.user@example.com",
user: &iam.User{
UserName: "test$.user@example.com",
},
expected: "test_user",
},
{
email: `jöhn.dœ@domain.com`, // Using non-ASCII characters.
user: &iam.User{
UserName: `jöhn.dœ@domain.com`, // Using non-ASCII characters.
},
expected: "jöhn_dœ",
},
{
email: `first+tag@email.com`, // The plus (+) sign is used for "sub-addressing" in some email services.
user: &iam.User{
UserName: `first+tag@email.com`, // The plus (+) sign is used for "sub-addressing" in some email services.
},
expected: "first_tag",
},
{
email: `email@sub.domain.com`, // Using a sub-domain.
user: &iam.User{
UserName: `email@sub.domain.com`, // Using a sub-domain.
},
expected: "email",
},
{
email: `"_quoted"@domain.com`, // Quoted strings can be part of the local-part.
user: &iam.User{
UserName: `"_quoted"@domain.com`, // Quoted strings can be part of the local-part.
},
expected: "quoted",
},
{
email: `name-o'mally@website.org`, // Single quote in the local-part.
user: &iam.User{
UserName: `name-o'mally@website.org`, // Single quote in the local-part.
},
expected: "name_o_mally",
},
{
email: `user%domain@external.com`, // Percent sign can be used for email routing in legacy systems.
user: &iam.User{
UserName: `user%domain@external.com`, // Percent sign can be used for email routing in legacy systems.
},
expected: "user_domain",
},
{
email: `long.name.with.dots@domain.net`, // Multiple dots in the local-part.
user: &iam.User{
UserName: `long.name.with.dots@domain.net`, // Multiple dots in the local-part.
},
expected: "long_name_with_dots",
},
{
email: `me&you@together.com`, // Using an ampersand (&) in the local-part.
user: &iam.User{
UserName: `me&you@together.com`, // Using an ampersand (&) in the local-part.
},
expected: "me_you",
},
{
email: `user!def!xyz@domain.org`, // The exclamation mark can be valid in some legacy systems.
user: &iam.User{
UserName: `user!def!xyz@domain.org`, // The exclamation mark can be valid in some legacy systems.
},
expected: "user_def_xyz",
},
{
email: `admin@ιντερνετ.com`, // Domain in non-ASCII characters (IDN or Internationalized Domain Name).
user: &iam.User{
UserName: `admin@ιντερνετ.com`, // Domain in non-ASCII characters (IDN or Internationalized Domain Name).
},
expected: "admin",
},
{
user: &iam.User{
UserName: `1706906c-c0a2-4c25-9f57-3a7aa3cb8123`,
DisplayName: "my-service-principal",
},
expected: "my_service_principal",
},
{
user: &iam.User{
UserName: `1706906c-c0a2-4c25-9f57-3a7aa3cb8123`,
// This service princpal has DisplayName (it's an optional property)
},
expected: "1706906c_c0a2_4c25_9f57_3a7aa3cb8123",
},
}

for _, tt := range tests {
assert.Equal(t, tt.expected, GetShortUserName(tt.email))
assert.Equal(t, tt.expected, GetShortUserName(tt.user))
}
}
2 changes: 1 addition & 1 deletion libs/template/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func loadHelpers(ctx context.Context) template.FuncMap {
return "", err
}
}
return auth.GetShortUserName(cachedUser.UserName), nil
return auth.GetShortUserName(cachedUser), nil
},
// Get the default workspace catalog. If there is no default, or if
// Unity Catalog is not enabled, return an empty string.
Expand Down