Skip to content

Commit db6b7af

Browse files
authored
Interactive profile selection on multiple host matches (#4604)
## Why When you have two profiles in `~/.databrickscfg` that point to the same workspace (e.g. `dev` and `staging` both with `host = https://myworkspace.cloud.databricks.com`), and you run a bundle command from a bundle that sets `workspace.host` but not `profile`, the CLI crashes with a confusing error telling you to set `DATABRICKS_CONFIG_PROFILE` or `--profile`. With the host-agnostic auth work, users are encouraged to have multiple profiles pointing at the same workspace (different auth methods, different roles). This "multiple profiles matched" error will become much more common. Today it's a paper cut; soon it'll be a wall. ## Changes **Before:** The CLI errored immediately with `multiple profiles matched: dev, staging: please set DATABRICKS_CONFIG_PROFILE or provide --profile flag`. No way to recover without restarting the command with a flag or env var. **Now:** When the CLI detects multiple profiles matching the same host, instead of erroring it: 1. Filters to workspace-compatible profiles (excludes account-only profiles) 2. If only one workspace profile remains — auto-selects it silently (no prompt, works in CI) 3. If multiple remain and the terminal is interactive — shows a picker so the user can choose 4. If multiple remain and non-interactive (CI, scripts) — returns the original error wrapped with actionable guidance showing three concrete fix options (databricks.yml, `--profile` flag, env var) Implementation is catch-and-retry in `configureBundle`: let `WorkspaceClientE()` run normally, catch `errMultipleProfiles`, resolve the ambiguity, set the profile on the workspace config, reset the `sync.Once` cache via `RetryWorkspaceClient()`, and retry. On retry the SDK uses named-profile resolution (since `Profile` is now set), which is the correct code path. New helpers: - `AsMultipleProfiles(err)` — extracts profile names from the error chain - `MatchProfileNames(names...)` — filters profiles by name - `RetryWorkspaceClient()` — resets the workspace client cache for retry - `promptForProfileByHost()` — interactive select UI for profile disambiguation Scope is bundle-only. `ResolveProfileFromHost` is only wired in `Workspace.Client()`, so non-bundle commands are unaffected. ## Test plan - [x] `AsMultipleProfiles` extracts names through the full wrapping chain; returns false for unrelated/nil errors - [x] `MatchProfileNames` matches correct profiles, rejects others, handles empty input - [x] `RetryWorkspaceClient` proves re-execution by changing config between attempts and asserting the error message changes - [x] Auto-select: two profiles match host, only one is workspace-compatible → auto-selected without prompt - [x] No workspace profiles: all matched profiles are account-only → original error returned - [x] Non-interactive multi-match: two workspace profiles, prompt not supported → error with guidance - [x] `SkipPrompt` respected: error returned, no prompt - [x] Interactive prompt fires: `PromptSupported: true` → select prompt starts on stderr - [x] Env-auth skip: `DATABRICKS_TOKEN` set → `errMultipleProfiles` never fires - [x] All existing bundle config tests continue to pass - [x] `make checks`, `make lintfull` pass
1 parent 93db3ca commit db6b7af

File tree

30 files changed

+430
-2
lines changed

30 files changed

+430
-2
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[ws-profile]
2+
host = $DATABRICKS_HOST
3+
token = $DATABRICKS_TOKEN
4+
5+
[acc-profile]
6+
host = $DATABRICKS_HOST
7+
account_id = abc123
8+
token = acc-token
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bundle:
2+
name: multi-profile-auto-select

acceptance/bundle/multi_profile/auto_select/out.test.toml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
>>> [CLI] bundle validate -o json
3+
{
4+
"name": "multi-profile-auto-select"
5+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Set up .databrickscfg with two profiles for the same host:
2+
# one workspace profile and one account profile.
3+
envsubst < .databrickscfg > out && mv out .databrickscfg
4+
5+
# Write databricks.yml with the actual host URL.
6+
cat > databricks.yml << EOF
7+
bundle:
8+
name: multi-profile-auto-select
9+
10+
workspace:
11+
host: $DATABRICKS_HOST
12+
EOF
13+
14+
export DATABRICKS_CONFIG_FILE=.databrickscfg
15+
unset DATABRICKS_HOST
16+
unset DATABRICKS_TOKEN
17+
18+
# Only one workspace-compatible profile exists (ws-profile).
19+
# The account-only profile (acc-profile) is filtered out.
20+
# Auto-select happens silently and validate succeeds.
21+
trace $CLI bundle validate -o json | jq '{name: .bundle.name}'
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[profile-1]
2+
host = $DATABRICKS_HOST
3+
token = t1
4+
5+
[profile-2]
6+
host = $DATABRICKS_HOST
7+
token = t2
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bundle:
2+
name: multi-profile-env-skip

acceptance/bundle/multi_profile/env_auth_skip/out.test.toml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
>>> [CLI] bundle validate -o json
3+
{
4+
"name": "multi-profile-env-skip"
5+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Set up .databrickscfg with two workspace profiles for the same host.
2+
envsubst < .databrickscfg > out && mv out .databrickscfg
3+
4+
cat > databricks.yml << EOF
5+
bundle:
6+
name: multi-profile-env-skip
7+
8+
workspace:
9+
host: $DATABRICKS_HOST
10+
EOF
11+
12+
export DATABRICKS_CONFIG_FILE=.databrickscfg
13+
# Keep DATABRICKS_HOST and DATABRICKS_TOKEN set — env auth takes precedence
14+
# over host-based profile matching, so errMultipleProfiles never fires.
15+
16+
trace $CLI bundle validate -o json | jq '{name: .bundle.name}'

0 commit comments

Comments
 (0)