From 39ecf382db6cc14bda788bf228a83ffc8f4144a7 Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 11 Mar 2026 15:55:12 +0100 Subject: [PATCH 1/5] Add support for default_profile in [__settings__] section Adds support for the __settings__ section in .databrickscfg, enabling default_profile to specify which profile to use when none is explicitly set. The resolved profile is written back to DatabricksConfig so downstream consumers (e.g. DatabricksCliCredentialsProvider) see it. Rejects __settings__ as a profile target to prevent self-referencing. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../com/databricks/sdk/core/ConfigLoader.java | 11 ++ .../databricks/sdk/DefaultProfileTest.java | 125 ++++++++++++++++++ .../testdata/default_profile/.databrickscfg | 6 + .../.databrickscfg | 5 + .../.databrickscfg | 10 ++ .../.databrickscfg | 6 + .../default_profile_precedence/.databrickscfg | 10 ++ .../.databrickscfg | 6 + 8 files changed, 179 insertions(+) create mode 100644 databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java create mode 100644 databricks-sdk-java/src/test/resources/testdata/default_profile/.databrickscfg create mode 100644 databricks-sdk-java/src/test/resources/testdata/default_profile_empty_settings/.databrickscfg create mode 100644 databricks-sdk-java/src/test/resources/testdata/default_profile_explicit_override/.databrickscfg create mode 100644 databricks-sdk-java/src/test/resources/testdata/default_profile_nonexistent/.databrickscfg create mode 100644 databricks-sdk-java/src/test/resources/testdata/default_profile_precedence/.databrickscfg create mode 100644 databricks-sdk-java/src/test/resources/testdata/default_profile_settings_self_ref/.databrickscfg diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java index ae531ffc0..66c251a25 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java @@ -94,6 +94,17 @@ static void loadFromConfig(DatabricksConfig cfg) throws IllegalAccessException { String profile = cfg.getProfile(); boolean hasExplicitProfile = !isNullOrEmpty(profile); + if (!hasExplicitProfile) { + SubnodeConfiguration settings = ini.getSection("__settings__"); + if (settings != null && !settings.isEmpty()) { + String defaultProfile = settings.getString("default_profile"); + if (!isNullOrEmpty(defaultProfile) && !"__settings__".equals(defaultProfile)) { + profile = defaultProfile; + hasExplicitProfile = true; + cfg.setProfile(profile); + } + } + } if (!hasExplicitProfile) { profile = "DEFAULT"; } diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java new file mode 100644 index 000000000..830c74810 --- /dev/null +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java @@ -0,0 +1,125 @@ +package com.databricks.sdk; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +import com.databricks.sdk.core.ConfigResolving; +import com.databricks.sdk.core.DatabricksConfig; +import com.databricks.sdk.core.DatabricksException; +import com.databricks.sdk.core.http.HttpClient; +import com.databricks.sdk.core.utils.TestOSUtils; +import org.junit.jupiter.api.Test; + +public class DefaultProfileTest implements ConfigResolving { + + private DatabricksConfig createConfigWithMockClient() { + HttpClient mockClient = mock(HttpClient.class); + return new DatabricksConfig().setHttpClient(mockClient); + } + + /** Test 1: default_profile resolves correctly and is written back to config */ + @Test + public void testDefaultProfileResolvesCorrectly() { + StaticEnv env = + new StaticEnv().with("HOME", TestOSUtils.resource("/testdata/default_profile")); + DatabricksConfig config = createConfigWithMockClient(); + resolveConfig(config, env); + config.authenticate(); + + assertEquals("pat", config.getAuthType()); + assertEquals("https://my-workspace.cloud.databricks.com", config.getHost()); + assertEquals("my-workspace", config.getProfile()); + } + + /** Test 2: default_profile takes precedence over [DEFAULT] */ + @Test + public void testDefaultProfileTakesPrecedenceOverDefault() { + StaticEnv env = + new StaticEnv() + .with("HOME", TestOSUtils.resource("/testdata/default_profile_precedence")); + DatabricksConfig config = createConfigWithMockClient(); + resolveConfig(config, env); + config.authenticate(); + + assertEquals("pat", config.getAuthType()); + assertEquals("https://my-workspace.cloud.databricks.com", config.getHost()); + } + + /** Test 3: Legacy fallback when no [__settings__] */ + @Test + public void testLegacyFallbackWhenNoSettings() { + StaticEnv env = new StaticEnv().with("HOME", TestOSUtils.resource("/testdata")); + DatabricksConfig config = createConfigWithMockClient(); + resolveConfig(config, env); + config.authenticate(); + + assertEquals("pat", config.getAuthType()); + assertEquals("https://dbc-XXXXXXXX-YYYY.cloud.databricks.com", config.getHost()); + } + + /** Test 4: Legacy fallback when default_profile is empty */ + @Test + public void testLegacyFallbackWhenDefaultProfileEmpty() { + StaticEnv env = + new StaticEnv() + .with("HOME", TestOSUtils.resource("/testdata/default_profile_empty_settings")); + DatabricksConfig config = createConfigWithMockClient(); + resolveConfig(config, env); + config.authenticate(); + + assertEquals("pat", config.getAuthType()); + assertEquals("https://default.cloud.databricks.com", config.getHost()); + } + + /** Test 5: default_profile = __settings__ is rejected and falls back to DEFAULT */ + @Test + public void testSettingsSelfReferenceIsRejected() { + StaticEnv env = + new StaticEnv() + .with("HOME", TestOSUtils.resource("/testdata/default_profile_settings_self_ref")); + DatabricksConfig config = createConfigWithMockClient(); + resolveConfig(config, env); + config.authenticate(); + + // __settings__ as a profile target should be ignored, falling back to [DEFAULT] + assertEquals("https://default.cloud.databricks.com", config.getHost()); + assertEquals("pat", config.getAuthType()); + } + + /** Test 6: Explicit --profile overrides default_profile */ + @Test + public void testExplicitProfileOverridesDefaultProfile() { + StaticEnv env = + new StaticEnv() + .with("DATABRICKS_CONFIG_PROFILE", "other") + .with("HOME", TestOSUtils.resource("/testdata/default_profile_explicit_override")); + DatabricksConfig config = createConfigWithMockClient(); + resolveConfig(config, env); + config.authenticate(); + + assertEquals("pat", config.getAuthType()); + assertEquals("https://other.cloud.databricks.com", config.getHost()); + } + + /** Test 7: default_profile pointing to nonexistent section */ + @Test + public void testDefaultProfileNonexistentSection() { + StaticEnv env = + new StaticEnv() + .with("HOME", TestOSUtils.resource("/testdata/default_profile_nonexistent")); + DatabricksConfig config = createConfigWithMockClient(); + + DatabricksException ex = + assertThrows( + DatabricksException.class, + () -> { + resolveConfig(config, env); + config.authenticate(); + }); + assertTrue( + ex.getMessage().contains("deleted-profile"), + "Error should mention the missing profile name: " + ex.getMessage()); + } +} diff --git a/databricks-sdk-java/src/test/resources/testdata/default_profile/.databrickscfg b/databricks-sdk-java/src/test/resources/testdata/default_profile/.databrickscfg new file mode 100644 index 000000000..9a3f6a2d8 --- /dev/null +++ b/databricks-sdk-java/src/test/resources/testdata/default_profile/.databrickscfg @@ -0,0 +1,6 @@ +[__settings__] +default_profile = my-workspace + +[my-workspace] +host = https://my-workspace.cloud.databricks.com +token = dapiXYZ diff --git a/databricks-sdk-java/src/test/resources/testdata/default_profile_empty_settings/.databrickscfg b/databricks-sdk-java/src/test/resources/testdata/default_profile_empty_settings/.databrickscfg new file mode 100644 index 000000000..46880f70e --- /dev/null +++ b/databricks-sdk-java/src/test/resources/testdata/default_profile_empty_settings/.databrickscfg @@ -0,0 +1,5 @@ +[__settings__] + +[DEFAULT] +host = https://default.cloud.databricks.com +token = dapiXYZ diff --git a/databricks-sdk-java/src/test/resources/testdata/default_profile_explicit_override/.databrickscfg b/databricks-sdk-java/src/test/resources/testdata/default_profile_explicit_override/.databrickscfg new file mode 100644 index 000000000..c3f9f79be --- /dev/null +++ b/databricks-sdk-java/src/test/resources/testdata/default_profile_explicit_override/.databrickscfg @@ -0,0 +1,10 @@ +[__settings__] +default_profile = my-workspace + +[my-workspace] +host = https://my-workspace.cloud.databricks.com +token = dapiXYZ + +[other] +host = https://other.cloud.databricks.com +token = dapiOTHER diff --git a/databricks-sdk-java/src/test/resources/testdata/default_profile_nonexistent/.databrickscfg b/databricks-sdk-java/src/test/resources/testdata/default_profile_nonexistent/.databrickscfg new file mode 100644 index 000000000..d2c144c92 --- /dev/null +++ b/databricks-sdk-java/src/test/resources/testdata/default_profile_nonexistent/.databrickscfg @@ -0,0 +1,6 @@ +[__settings__] +default_profile = deleted-profile + +[my-workspace] +host = https://my-workspace.cloud.databricks.com +token = dapiXYZ diff --git a/databricks-sdk-java/src/test/resources/testdata/default_profile_precedence/.databrickscfg b/databricks-sdk-java/src/test/resources/testdata/default_profile_precedence/.databrickscfg new file mode 100644 index 000000000..ac8f295d6 --- /dev/null +++ b/databricks-sdk-java/src/test/resources/testdata/default_profile_precedence/.databrickscfg @@ -0,0 +1,10 @@ +[__settings__] +default_profile = my-workspace + +[DEFAULT] +host = https://default.cloud.databricks.com +token = dapiOLD + +[my-workspace] +host = https://my-workspace.cloud.databricks.com +token = dapiXYZ diff --git a/databricks-sdk-java/src/test/resources/testdata/default_profile_settings_self_ref/.databrickscfg b/databricks-sdk-java/src/test/resources/testdata/default_profile_settings_self_ref/.databrickscfg new file mode 100644 index 000000000..05f711147 --- /dev/null +++ b/databricks-sdk-java/src/test/resources/testdata/default_profile_settings_self_ref/.databrickscfg @@ -0,0 +1,6 @@ +[__settings__] +default_profile = __settings__ + +[DEFAULT] +host = https://default.cloud.databricks.com +token = dapiXYZ From be0e584d55d1ada1b0cbfb0af743c000d882e244 Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 11 Mar 2026 17:04:31 +0100 Subject: [PATCH 2/5] Reject __settings__ as a reserved profile target Keep default_profile resolution aligned with the other SDKs by preserving the resolved profile name and surfacing bad settings targets instead of silently falling back. --- .../com/databricks/sdk/core/ConfigLoader.java | 21 +++++++---- .../databricks/sdk/DefaultProfileTest.java | 37 ++++++++++++++++--- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java index 66c251a25..757f1dc5d 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java @@ -19,6 +19,7 @@ @InternalApi public class ConfigLoader { private static final Logger LOG = LoggerFactory.getLogger(ConfigLoader.class); + private static final String SETTINGS_SECTION = "__settings__"; private static final List accessors = attributeAccessors(); @@ -94,23 +95,26 @@ static void loadFromConfig(DatabricksConfig cfg) throws IllegalAccessException { String profile = cfg.getProfile(); boolean hasExplicitProfile = !isNullOrEmpty(profile); + boolean hasDefaultProfileSetting = false; if (!hasExplicitProfile) { - SubnodeConfiguration settings = ini.getSection("__settings__"); + SubnodeConfiguration settings = ini.getSection(SETTINGS_SECTION); if (settings != null && !settings.isEmpty()) { String defaultProfile = settings.getString("default_profile"); - if (!isNullOrEmpty(defaultProfile) && !"__settings__".equals(defaultProfile)) { + if (defaultProfile != null) { + defaultProfile = defaultProfile.trim(); + } + if (!isNullOrEmpty(defaultProfile)) { profile = defaultProfile; - hasExplicitProfile = true; - cfg.setProfile(profile); + hasDefaultProfileSetting = true; } } } - if (!hasExplicitProfile) { + if (!hasExplicitProfile && !hasDefaultProfileSetting) { profile = "DEFAULT"; } - SubnodeConfiguration section = ini.getSection(profile); + SubnodeConfiguration section = SETTINGS_SECTION.equals(profile) ? null : ini.getSection(profile); boolean sectionNotPresent = section == null || section.isEmpty(); - if (sectionNotPresent && !hasExplicitProfile) { + if (sectionNotPresent && !hasExplicitProfile && !hasDefaultProfileSetting) { LOG.info("{} has no {} profile configured", configFile, profile); return; } @@ -118,6 +122,9 @@ static void loadFromConfig(DatabricksConfig cfg) throws IllegalAccessException { String msg = String.format("resolve: %s has no %s profile configured", configFile, profile); throw new DatabricksException(msg); } + if (hasDefaultProfileSetting) { + cfg.setProfile(profile); + } for (ConfigAttributeAccessor accessor : accessors) { String value = section.getString(accessor.getName()); diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java index 830c74810..eb2526f1b 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java @@ -73,19 +73,24 @@ public void testLegacyFallbackWhenDefaultProfileEmpty() { assertEquals("https://default.cloud.databricks.com", config.getHost()); } - /** Test 5: default_profile = __settings__ is rejected and falls back to DEFAULT */ + /** Test 5: default_profile = __settings__ is rejected */ @Test public void testSettingsSelfReferenceIsRejected() { StaticEnv env = new StaticEnv() .with("HOME", TestOSUtils.resource("/testdata/default_profile_settings_self_ref")); DatabricksConfig config = createConfigWithMockClient(); - resolveConfig(config, env); - config.authenticate(); - // __settings__ as a profile target should be ignored, falling back to [DEFAULT] - assertEquals("https://default.cloud.databricks.com", config.getHost()); - assertEquals("pat", config.getAuthType()); + DatabricksException ex = + assertThrows( + DatabricksException.class, + () -> { + resolveConfig(config, env); + config.authenticate(); + }); + assertTrue( + ex.getMessage().contains("has no __settings__ profile configured"), + "Error should reject __settings__ as a profile target: " + ex.getMessage()); } /** Test 6: Explicit --profile overrides default_profile */ @@ -103,6 +108,26 @@ public void testExplicitProfileOverridesDefaultProfile() { assertEquals("https://other.cloud.databricks.com", config.getHost()); } + @Test + public void testExplicitSettingsSectionProfileIsRejected() { + StaticEnv env = + new StaticEnv() + .with("DATABRICKS_CONFIG_PROFILE", "__settings__") + .with("HOME", TestOSUtils.resource("/testdata/default_profile")); + DatabricksConfig config = createConfigWithMockClient(); + + DatabricksException ex = + assertThrows( + DatabricksException.class, + () -> { + resolveConfig(config, env); + config.authenticate(); + }); + assertTrue( + ex.getMessage().contains("has no __settings__ profile configured"), + "Error should reject __settings__ as a profile target: " + ex.getMessage()); + } + /** Test 7: default_profile pointing to nonexistent section */ @Test public void testDefaultProfileNonexistentSection() { From 5c59decd0db5fe1b500b307310a0847a201b81a7 Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 11 Mar 2026 17:27:32 +0100 Subject: [PATCH 3/5] Fix spotless formatting and add NEXT_CHANGELOG entry --- NEXT_CHANGELOG.md | 1 + .../main/java/com/databricks/sdk/core/ConfigLoader.java | 3 ++- .../test/java/com/databricks/sdk/DefaultProfileTest.java | 9 +++------ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 3d39694b1..20b06b208 100755 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -3,6 +3,7 @@ ## Release v0.100.0 ### New Features and Improvements +* Support `default_profile` in `[__settings__]` section of `.databrickscfg` for consistent default profile resolution across CLI and SDKs. ### Bug Fixes diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java index 757f1dc5d..453b87608 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java @@ -112,7 +112,8 @@ static void loadFromConfig(DatabricksConfig cfg) throws IllegalAccessException { if (!hasExplicitProfile && !hasDefaultProfileSetting) { profile = "DEFAULT"; } - SubnodeConfiguration section = SETTINGS_SECTION.equals(profile) ? null : ini.getSection(profile); + SubnodeConfiguration section = + SETTINGS_SECTION.equals(profile) ? null : ini.getSection(profile); boolean sectionNotPresent = section == null || section.isEmpty(); if (sectionNotPresent && !hasExplicitProfile && !hasDefaultProfileSetting) { LOG.info("{} has no {} profile configured", configFile, profile); diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java index eb2526f1b..df5937bac 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java @@ -22,8 +22,7 @@ private DatabricksConfig createConfigWithMockClient() { /** Test 1: default_profile resolves correctly and is written back to config */ @Test public void testDefaultProfileResolvesCorrectly() { - StaticEnv env = - new StaticEnv().with("HOME", TestOSUtils.resource("/testdata/default_profile")); + StaticEnv env = new StaticEnv().with("HOME", TestOSUtils.resource("/testdata/default_profile")); DatabricksConfig config = createConfigWithMockClient(); resolveConfig(config, env); config.authenticate(); @@ -37,8 +36,7 @@ public void testDefaultProfileResolvesCorrectly() { @Test public void testDefaultProfileTakesPrecedenceOverDefault() { StaticEnv env = - new StaticEnv() - .with("HOME", TestOSUtils.resource("/testdata/default_profile_precedence")); + new StaticEnv().with("HOME", TestOSUtils.resource("/testdata/default_profile_precedence")); DatabricksConfig config = createConfigWithMockClient(); resolveConfig(config, env); config.authenticate(); @@ -132,8 +130,7 @@ public void testExplicitSettingsSectionProfileIsRejected() { @Test public void testDefaultProfileNonexistentSection() { StaticEnv env = - new StaticEnv() - .with("HOME", TestOSUtils.resource("/testdata/default_profile_nonexistent")); + new StaticEnv().with("HOME", TestOSUtils.resource("/testdata/default_profile_nonexistent")); DatabricksConfig config = createConfigWithMockClient(); DatabricksException ex = From c417dc77cb4d7b87064898d5e55a05fc614aca35 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 16 Mar 2026 16:49:47 +0100 Subject: [PATCH 4/5] Extract resolveProfile to simplify loadFromConfig Move all profile resolution logic (explicit, __settings__, DEFAULT fallback) into a single resolveProfile method that returns the profile name and whether it is a silent fallback. This replaces the two-boolean pattern (hasExplicitProfile, hasDefaultProfileSetting) with a clearer isFallback flag, and keeps __settings__ knowledge out of loadFromConfig entirely. Also improves error messages when __settings__ is used as a profile name: now says "reserved section name" instead of the generic "has no __settings__ profile configured". Co-authored-by: Isaac --- .../com/databricks/sdk/core/ConfigLoader.java | 83 +++++++++++++------ .../databricks/sdk/DefaultProfileTest.java | 4 +- 2 files changed, 59 insertions(+), 28 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java index 453b87608..2930c0340 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java @@ -93,37 +93,22 @@ static void loadFromConfig(DatabricksConfig cfg) throws IllegalAccessException { INIConfiguration ini = parseDatabricksCfg(configFile, isDefaultConfig); if (ini == null) return; - String profile = cfg.getProfile(); - boolean hasExplicitProfile = !isNullOrEmpty(profile); - boolean hasDefaultProfileSetting = false; - if (!hasExplicitProfile) { - SubnodeConfiguration settings = ini.getSection(SETTINGS_SECTION); - if (settings != null && !settings.isEmpty()) { - String defaultProfile = settings.getString("default_profile"); - if (defaultProfile != null) { - defaultProfile = defaultProfile.trim(); - } - if (!isNullOrEmpty(defaultProfile)) { - profile = defaultProfile; - hasDefaultProfileSetting = true; - } - } - } - if (!hasExplicitProfile && !hasDefaultProfileSetting) { - profile = "DEFAULT"; - } - SubnodeConfiguration section = - SETTINGS_SECTION.equals(profile) ? null : ini.getSection(profile); + String[] resolved = resolveProfile(cfg.getProfile(), ini, configFile.toString()); + String profile = resolved[0]; + boolean isFallback = "true".equals(resolved[1]); + + SubnodeConfiguration section = ini.getSection(profile); boolean sectionNotPresent = section == null || section.isEmpty(); - if (sectionNotPresent && !hasExplicitProfile && !hasDefaultProfileSetting) { - LOG.info("{} has no {} profile configured", configFile, profile); - return; - } if (sectionNotPresent) { + if (isFallback) { + LOG.info("{} has no {} profile configured", configFile, profile); + return; + } String msg = String.format("resolve: %s has no %s profile configured", configFile, profile); throw new DatabricksException(msg); } - if (hasDefaultProfileSetting) { + + if (!isFallback) { cfg.setProfile(profile); } @@ -136,6 +121,52 @@ static void loadFromConfig(DatabricksConfig cfg) throws IllegalAccessException { } } + /** + * Resolves which profile to use from the config file. + * + *

Resolution order: + * + *

    + *
  1. Explicit profile (flag, env var, or programmatic config) with isFallback=false + *
  2. {@code [__settings__].default_profile} with isFallback=false + *
  3. {@code "DEFAULT"} with isFallback=true + *
+ * + * @return a two-element array: [profileName, "true"/"false" for isFallback] + * @throws DatabricksException if the resolved profile is the reserved __settings__ section + */ + static String[] resolveProfile( + String requestedProfile, INIConfiguration ini, String configFile) { + if (!isNullOrEmpty(requestedProfile)) { + if (SETTINGS_SECTION.equals(requestedProfile)) { + throw new DatabricksException( + String.format( + "%s: %s is a reserved section name and cannot be used as a profile", + configFile, SETTINGS_SECTION)); + } + return new String[] {requestedProfile, "false"}; + } + + SubnodeConfiguration settings = ini.getSection(SETTINGS_SECTION); + if (settings != null && !settings.isEmpty()) { + String defaultProfile = settings.getString("default_profile"); + if (defaultProfile != null) { + defaultProfile = defaultProfile.trim(); + } + if (!isNullOrEmpty(defaultProfile)) { + if (SETTINGS_SECTION.equals(defaultProfile)) { + throw new DatabricksException( + String.format( + "%s: %s is a reserved section name and cannot be used as a profile", + configFile, SETTINGS_SECTION)); + } + return new String[] {defaultProfile, "false"}; + } + } + + return new String[] {"DEFAULT", "true"}; + } + private static INIConfiguration parseDatabricksCfg(String configFile, boolean isDefaultConfig) { INIConfiguration iniConfig = new INIConfiguration(); try (FileReader reader = new FileReader(configFile)) { diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java index df5937bac..2df78a1f4 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/DefaultProfileTest.java @@ -87,7 +87,7 @@ public void testSettingsSelfReferenceIsRejected() { config.authenticate(); }); assertTrue( - ex.getMessage().contains("has no __settings__ profile configured"), + ex.getMessage().contains("reserved section name"), "Error should reject __settings__ as a profile target: " + ex.getMessage()); } @@ -122,7 +122,7 @@ public void testExplicitSettingsSectionProfileIsRejected() { config.authenticate(); }); assertTrue( - ex.getMessage().contains("has no __settings__ profile configured"), + ex.getMessage().contains("reserved section name"), "Error should reject __settings__ as a profile target: " + ex.getMessage()); } From d029dd287ca67f942da348117dd5a3dcdd16f625 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 16 Mar 2026 16:55:54 +0100 Subject: [PATCH 5/5] Fix spotless formatting for resolveProfile signature Co-authored-by: Isaac --- .../src/main/java/com/databricks/sdk/core/ConfigLoader.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java index 2930c0340..a1a6214e9 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/ConfigLoader.java @@ -135,8 +135,7 @@ static void loadFromConfig(DatabricksConfig cfg) throws IllegalAccessException { * @return a two-element array: [profileName, "true"/"false" for isFallback] * @throws DatabricksException if the resolved profile is the reserved __settings__ section */ - static String[] resolveProfile( - String requestedProfile, INIConfiguration ini, String configFile) { + static String[] resolveProfile(String requestedProfile, INIConfiguration ini, String configFile) { if (!isNullOrEmpty(requestedProfile)) { if (SETTINGS_SECTION.equals(requestedProfile)) { throw new DatabricksException(