Skip to content

Commit 3f72a7f

Browse files
committed
Wire default_profile into workspace client resolution
When no --profile flag or DATABRICKS_CONFIG_PROFILE env var is set, the CLI now honors the explicit default_profile setting from [__databricks-settings__] before the SDK falls back to the DEFAULT section. Also aligns auth describe to only show the configured default (not fallback heuristics like single-profile auto-default).
1 parent ea4a9e0 commit 3f72a7f

6 files changed

Lines changed: 212 additions & 14 deletions

File tree

cmd/auth/describe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func getAuthDetails(cmd *cobra.Command, cfg *config.Config, showSensitive bool)
183183
profile := cfg.Profile
184184
if profile == "" {
185185
profile = "default"
186-
if resolved, err := databrickscfg.GetDefaultProfile(cmd.Context(), cfg.ConfigFile); err == nil && resolved != "" {
186+
if resolved, err := databrickscfg.GetConfiguredDefaultProfile(cmd.Context(), cfg.ConfigFile); err == nil && resolved != "" {
187187
profile = fmt.Sprintf("default (%s)", resolved)
188188
}
189189
}

cmd/auth/profiles_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestProfiles(t *testing.T) {
4545
}
4646

4747
func TestProfilesDefaultMarker(t *testing.T) {
48-
ctx := context.Background()
48+
ctx := t.Context()
4949
dir := t.TempDir()
5050
configFile := filepath.Join(dir, ".databrickscfg")
5151

cmd/root/auth.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
"github.com/databricks/cli/libs/auth"
1010
"github.com/databricks/cli/libs/cmdctx"
1111
"github.com/databricks/cli/libs/cmdio"
12+
"github.com/databricks/cli/libs/databrickscfg"
1213
"github.com/databricks/cli/libs/databrickscfg/profile"
14+
envlib "github.com/databricks/cli/libs/env"
1315
"github.com/databricks/cli/libs/logdiag"
1416
"github.com/databricks/databricks-sdk-go"
1517
"github.com/databricks/databricks-sdk-go/config"
@@ -194,6 +196,17 @@ func MustWorkspaceClient(cmd *cobra.Command, args []string) error {
194196
cfg.Profile = profile
195197
}
196198

199+
// If --profile and DATABRICKS_CONFIG_PROFILE are both unset, honor the
200+
// explicit [__databricks-settings__].default_profile setting before the
201+
// SDK falls back to the DEFAULT section.
202+
if cfg.Profile == "" && envlib.Get(ctx, "DATABRICKS_CONFIG_PROFILE") == "" {
203+
configFilePath := envlib.Get(ctx, "DATABRICKS_CONFIG_FILE")
204+
resolvedProfile, err := databrickscfg.GetConfiguredDefaultProfile(ctx, configFilePath)
205+
if err == nil && resolvedProfile != "" {
206+
cfg.Profile = resolvedProfile
207+
}
208+
}
209+
197210
_, isTargetFlagSet := targetFlagValue(cmd)
198211
// If the profile flag is set but the target flag is not, we should skip loading the bundle configuration.
199212
if !isTargetFlagSet && hasProfileFlag {

cmd/root/auth_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,114 @@ func TestMustAnyClientWithEmptyDatabricksCfg(t *testing.T) {
323323
_, err = MustAnyClient(cmd, []string{})
324324
require.ErrorContains(t, err, "does not contain account profiles")
325325
}
326+
327+
func TestMustWorkspaceClientDefaultProfilePrecedence(t *testing.T) {
328+
testutil.CleanupEnvironment(t)
329+
330+
configFile := filepath.Join(t.TempDir(), ".databrickscfg")
331+
err := os.WriteFile(configFile, []byte(`
332+
[__databricks-settings__]
333+
default_profile = settings-profile
334+
335+
[DEFAULT]
336+
host = https://default.cloud.databricks.com
337+
token = default-token
338+
339+
[settings-profile]
340+
host = https://settings.cloud.databricks.com
341+
token = settings-token
342+
343+
[env-profile]
344+
host = https://env.cloud.databricks.com
345+
token = env-token
346+
347+
[flag-profile]
348+
host = https://flag.cloud.databricks.com
349+
token = flag-token
350+
`), 0o600)
351+
require.NoError(t, err)
352+
353+
testCases := []struct {
354+
name string
355+
profileFlag string
356+
envProfile string
357+
wantProfile string
358+
wantHost string
359+
}{
360+
{
361+
name: "settings default is used when flag and env are unset",
362+
wantProfile: "settings-profile",
363+
wantHost: "https://settings.cloud.databricks.com",
364+
},
365+
{
366+
name: "env var takes precedence over settings default",
367+
envProfile: "env-profile",
368+
wantProfile: "env-profile",
369+
wantHost: "https://env.cloud.databricks.com",
370+
},
371+
{
372+
name: "profile flag takes precedence over env var",
373+
profileFlag: "flag-profile",
374+
envProfile: "env-profile",
375+
wantProfile: "flag-profile",
376+
wantHost: "https://flag.cloud.databricks.com",
377+
},
378+
}
379+
380+
for _, tc := range testCases {
381+
t.Run(tc.name, func(t *testing.T) {
382+
testutil.CleanupEnvironment(t)
383+
t.Setenv("DATABRICKS_CONFIG_FILE", configFile)
384+
if tc.envProfile != "" {
385+
t.Setenv("DATABRICKS_CONFIG_PROFILE", tc.envProfile)
386+
}
387+
388+
ctx := cmdio.MockDiscard(context.Background())
389+
ctx = SkipLoadBundle(ctx)
390+
cmd := New(ctx)
391+
392+
if tc.profileFlag != "" {
393+
err := cmd.Flag("profile").Value.Set(tc.profileFlag)
394+
require.NoError(t, err)
395+
}
396+
397+
err := MustWorkspaceClient(cmd, []string{})
398+
require.NoError(t, err)
399+
400+
w := cmdctx.WorkspaceClient(cmd.Context())
401+
require.NotNil(t, w)
402+
assert.Equal(t, tc.wantProfile, w.Config.Profile)
403+
assert.Equal(t, tc.wantHost, w.Config.Host)
404+
})
405+
}
406+
}
407+
408+
func TestMustWorkspaceClientWithoutConfiguredDefaultFallsBackToDefaultSection(t *testing.T) {
409+
testutil.CleanupEnvironment(t)
410+
411+
configFile := filepath.Join(t.TempDir(), ".databrickscfg")
412+
err := os.WriteFile(configFile, []byte(`
413+
[DEFAULT]
414+
host = https://default.cloud.databricks.com
415+
token = default-token
416+
417+
[named-profile]
418+
host = https://named.cloud.databricks.com
419+
token = named-token
420+
`), 0o600)
421+
require.NoError(t, err)
422+
423+
t.Setenv("DATABRICKS_CONFIG_FILE", configFile)
424+
425+
ctx := cmdio.MockDiscard(context.Background())
426+
ctx = SkipLoadBundle(ctx)
427+
cmd := New(ctx)
428+
429+
err = MustWorkspaceClient(cmd, []string{})
430+
require.NoError(t, err)
431+
432+
w := cmdctx.WorkspaceClient(cmd.Context())
433+
require.NotNil(t, w)
434+
assert.Equal(t, "", w.Config.Profile)
435+
assert.Equal(t, "https://default.cloud.databricks.com", w.Config.Host)
436+
}

libs/databrickscfg/ops.go

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,34 @@ const defaultComment = "The profile defined in the DEFAULT section is to be used
2020

2121
const databricksSettingsSection = "__databricks-settings__"
2222

23+
// GetConfiguredDefaultProfile returns the explicitly configured default profile
24+
// by loading the config file at configFilePath.
25+
// Returns "" if the file doesn't exist or default_profile is not set.
26+
func GetConfiguredDefaultProfile(ctx context.Context, configFilePath string) (string, error) {
27+
configFile, err := loadConfigFile(ctx, configFilePath)
28+
if err != nil {
29+
return "", err
30+
}
31+
if configFile == nil {
32+
return "", nil
33+
}
34+
return GetConfiguredDefaultProfileFrom(configFile), nil
35+
}
36+
37+
// GetConfiguredDefaultProfileFrom returns the explicit default profile from
38+
// [__databricks-settings__].default_profile, or "" when it is not set.
39+
func GetConfiguredDefaultProfileFrom(configFile *config.File) string {
40+
section, err := configFile.GetSection(databricksSettingsSection)
41+
if err != nil {
42+
return ""
43+
}
44+
key, err := section.GetKey("default_profile")
45+
if err != nil {
46+
return ""
47+
}
48+
return key.String()
49+
}
50+
2351
// GetDefaultProfile returns the name of the default profile by loading the
2452
// config file at configFilePath. Returns "" if the file doesn't exist.
2553
// See GetDefaultProfileFrom for resolution order.
@@ -68,18 +96,14 @@ func resolveConfigFilePath(ctx context.Context, filename string) (string, error)
6896

6997
// GetDefaultProfileFrom returns the name of the default profile from an
7098
// already-loaded config file. It uses the following resolution order:
71-
// 1. Explicit default_profile key in [databricks-cli-settings].
99+
// 1. Explicit default_profile key in [__databricks-settings__].
72100
// 2. If there is exactly one profile in the file, return it.
73101
// 3. If a profile named DEFAULT exists, return it.
74102
// 4. Empty string (no default).
75103
func GetDefaultProfileFrom(configFile *config.File) string {
76104
// 1. Check for explicit default_profile setting.
77-
section, err := configFile.GetSection(databricksSettingsSection)
78-
if err == nil {
79-
key, err := section.GetKey("default_profile")
80-
if err == nil && key.String() != "" {
81-
return key.String()
82-
}
105+
if profile := GetConfiguredDefaultProfileFrom(configFile); profile != "" {
106+
return profile
83107
}
84108

85109
// Collect profile sections (sections that have a "host" key, excluding
@@ -112,7 +136,7 @@ func GetDefaultProfileFrom(configFile *config.File) string {
112136
return ""
113137
}
114138

115-
// SetDefaultProfile writes the default_profile key to the [databricks-cli-settings] section.
139+
// SetDefaultProfile writes the default_profile key to the [__databricks-settings__] section.
116140
func SetDefaultProfile(ctx context.Context, profileName, configFilePath string) error {
117141
configFile, err := loadOrCreateConfigFile(ctx, configFilePath)
118142
if err != nil {

libs/databrickscfg/ops_test.go

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ func TestGetDefaultProfile(t *testing.T) {
231231
err := os.WriteFile(path, []byte(tc.content), 0o600)
232232
require.NoError(t, err)
233233

234-
got, err := GetDefaultProfile(context.Background(), path)
234+
got, err := GetDefaultProfile(t.Context(), path)
235235
require.NoError(t, err)
236236
assert.Equal(t, tc.want, got)
237237
})
@@ -240,7 +240,57 @@ func TestGetDefaultProfile(t *testing.T) {
240240

241241
func TestGetDefaultProfile_NoFile(t *testing.T) {
242242
path := filepath.Join(t.TempDir(), "databrickscfg")
243-
got, err := GetDefaultProfile(context.Background(), path)
243+
got, err := GetDefaultProfile(t.Context(), path)
244+
require.NoError(t, err)
245+
assert.Equal(t, "", got)
246+
// Verify the file was NOT created as a side effect.
247+
assert.NoFileExists(t, path)
248+
}
249+
250+
func TestGetConfiguredDefaultProfile(t *testing.T) {
251+
testCases := []struct {
252+
name string
253+
content string
254+
want string
255+
}{
256+
{
257+
name: "explicit default_profile setting",
258+
content: "[__databricks-settings__]\ndefault_profile = my-workspace\n\n[my-workspace]\nhost = https://abc\n",
259+
want: "my-workspace",
260+
},
261+
{
262+
name: "single profile fallback is ignored",
263+
content: "[profile1]\nhost = https://abc\n",
264+
want: "",
265+
},
266+
{
267+
name: "DEFAULT fallback is ignored",
268+
content: "[DEFAULT]\nhost = https://abc\n\n[profile2]\nhost = https://def\n",
269+
want: "",
270+
},
271+
{
272+
name: "settings section without key",
273+
content: "[__databricks-settings__]\n\n[profile1]\nhost = https://abc\n",
274+
want: "",
275+
},
276+
}
277+
278+
for _, tc := range testCases {
279+
t.Run(tc.name, func(t *testing.T) {
280+
path := filepath.Join(t.TempDir(), "databrickscfg")
281+
err := os.WriteFile(path, []byte(tc.content), 0o600)
282+
require.NoError(t, err)
283+
284+
got, err := GetConfiguredDefaultProfile(t.Context(), path)
285+
require.NoError(t, err)
286+
assert.Equal(t, tc.want, got)
287+
})
288+
}
289+
}
290+
291+
func TestGetConfiguredDefaultProfile_NoFile(t *testing.T) {
292+
path := filepath.Join(t.TempDir(), "databrickscfg")
293+
got, err := GetConfiguredDefaultProfile(t.Context(), path)
244294
require.NoError(t, err)
245295
assert.Equal(t, "", got)
246296
// Verify the file was NOT created as a side effect.
@@ -276,7 +326,7 @@ func TestSetDefaultProfile(t *testing.T) {
276326

277327
for _, tc := range testCases {
278328
t.Run(tc.name, func(t *testing.T) {
279-
ctx := context.Background()
329+
ctx := t.Context()
280330
path := filepath.Join(t.TempDir(), "databrickscfg")
281331
err := os.WriteFile(path, []byte(tc.initial), 0o600)
282332
require.NoError(t, err)
@@ -292,7 +342,7 @@ func TestSetDefaultProfile(t *testing.T) {
292342
}
293343

294344
func TestSetDefaultProfile_RoundTrip(t *testing.T) {
295-
ctx := context.Background()
345+
ctx := t.Context()
296346
path := filepath.Join(t.TempDir(), "databrickscfg")
297347

298348
// Start with a profile.

0 commit comments

Comments
 (0)