Commit db6b7af
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` pass1 parent 93db3ca commit db6b7af
File tree
30 files changed
+430
-2
lines changed- acceptance/bundle/multi_profile
- auto_select
- env_auth_skip
- no_workspace_profiles
- non_interactive_error
- bundle
- cmd/root
- libs/databrickscfg
- profile
30 files changed
+430
-2
lines changedLines changed: 8 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
Lines changed: 2 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
Lines changed: 7 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
Lines changed: 2 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
0 commit comments