Add support for default_profile in [__settings__] section#1534
Add support for default_profile in [__settings__] section#1534simonfaltum merged 10 commits intomainfrom
Conversation
When no profile is explicitly configured, the SDK now checks for a [__settings__].default_profile key in .databrickscfg before falling back to the DEFAULT section. This aligns the SDK with the CLI's 'databricks auth switch' command, which writes the user's chosen default profile to this section. Profile resolution order: 1. Explicit profile (--profile flag, env var, or programmatic) 2. [__settings__].default_profile (new) 3. [DEFAULT] section (legacy fallback) The [__settings__] section is never treated as a profile. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> Signed-off-by: simon <[email protected]>
Signed-off-by: simon <[email protected]>
- Reject default_profile = __settings__ (self-reference falls through to DEFAULT instead of trying to load __settings__ as a profile) - Add test for the self-reference guard with dedicated fixture - Differentiate TestConfigFile_DefaultProfileResolves from the precedence test by using a fixture without a [DEFAULT] section - Strengthen TestConfigFile_SettingsSectionNotAProfile to verify __settings__ is present in SectionStrings (documenting that callers must filter it) and that resolveDefaultProfile still rejects it
Persist the resolved profile name and reject the reserved settings section as a profile target so OAuth cache keys and CLI auth keep using the selected profile.
|
I think the logic in Also, unless I'm missing something, the branch where What would you think of moving all the resolution logic (including the // resolveProfile returns the profile name to use and whether it is a
// default fallback:
// - If cfg.Profile is set explicitly, returns it with false.
// - If [__settings__].default_profile is set, returns it with false.
// - Otherwise, returns "DEFAULT" with true.
//
// Returns an error if cfg.Profile is the reserved __settings__ section name.
func resolveProfile(cfg *Config, f *File) (string, bool, error) {
if cfg.Profile != "" {
if cfg.Profile == settingsSection {
return "", false, fmt.Errorf(
"%s is a reserved section name and cannot be used as a profile", settingsSection)
}
return cfg.Profile, false, nil
}
section, err := f.GetSection(settingsSection)
if err == nil {
key, err := section.GetKey("default_profile")
if err == nil {
v := strings.TrimSpace(key.String())
if v != "" && v != settingsSection {
return v, false, nil
}
}
}
return "DEFAULT", true, nil
}Then profile, isDefault, err := resolveProfile(cfg, configFile)
if err != nil {
return err
}
profileValues := configFile.Section(profile)
if len(profileValues.Keys()) == 0 {
if isDefault {
logger.Debugf(context.Background(), "%s has no %s profile configured", configFile.Path(), profile)
return nil
}
return fmt.Errorf("%s has no %s profile configured", configFile.Path(), profile)
}
err = cfg.loadProfileFromSection(profileValues)
if err != nil {
return fmt.Errorf("%s %s profile: %w", configFile.Path(), profile, err)
}
if !isDefault {
cfg.Profile = profile
}
return nilThe wins:
|
Replaces resolveDefaultProfile and the two-boolean logic in Configure with a single resolveProfile(requestedProfile, file) function that returns (profile, isFallback, error). This encapsulates all __settings__ knowledge in one place and makes Configure read cleanly with a single isFallback boolean instead of !hasExplicitProfile && !hasDefaultProfileSetting. The __settings__ self-reference case now returns a clear "reserved section name" error instead of a generic "no profile configured" message. Co-authored-by: Isaac Signed-off-by: simon <[email protected]>
Simplify TestConfigFile_SettingsSectionNotAProfile: replace the loop with a direct assert.Contains since resolveProfile now validates against __settings__ via error return. Add TestConfigFile_ExplicitDefaultProfileViaSetting to document that default_profile = DEFAULT is treated as an explicit selection (sets cfg.Profile, errors on missing section) rather than as the silent legacy fallback. Co-authored-by: Isaac Signed-off-by: simon <[email protected]>
|
If integration tests don't run automatically, an authorized user can run them manually by following the instructions below: Trigger: Inputs:
Checks will be approved automatically on success. |
renaudhartert-db
left a comment
There was a problem hiding this comment.
Thanks, looks great!
Changes
When no profile is explicitly configured, the SDK now checks for a
[__settings__].default_profilekey in.databrickscfgbefore fallingback to the
DEFAULTsection. This aligns the SDK with the CLI'sdatabricks auth switchcommand, which writes the user's chosendefault profile to this section.
Profile resolution order:
--profileflag, env var, or programmatic setting)[__settings__].default_profile(new)[DEFAULT]section (legacy fallback)The
[__settings__]section is never treated as a profile.Backwards compatible: existing configs without
[__settings__]behave identically.Tests
Seven test scenarios covering:
default_profileresolves correctlydefault_profiletakes precedence over[DEFAULT][__settings__]default_profileis empty[__settings__]is not a profile--profileoverridesdefault_profiledefault_profilepointing to nonexistent section returns error