Skip to content

Extract shared SelectProfile helper to eliminate duplicate profile pickers#4647

Open
mihaimitrea-db wants to merge 32 commits intomainfrom
mihaimitrea-db/stack/auth_logout_deduplication
Open

Extract shared SelectProfile helper to eliminate duplicate profile pickers#4647
mihaimitrea-db wants to merge 32 commits intomainfrom
mihaimitrea-db/stack/auth_logout_deduplication

Conversation

@mihaimitrea-db
Copy link
Collaborator

@mihaimitrea-db mihaimitrea-db commented Mar 3, 2026

🥞 Stacked PR

Use this link to review incremental changes.


Four places built nearly identical promptui.Select prompts for interactive profile selection (auth logout, auth token, cmd/root/auth.go, cmd/root/bundle.go). This PR extracts a reusable profile.SelectProfile function that accepts a declarative SelectConfig with label, profiles, and template strings, replacing all four implementations.

Changes

  • Add profile.SelectProfile in libs/databrickscfg/profile/select.go — a shared interactive profile picker that accepts a SelectConfig (label, profiles, template strings) and returns the selected profile name.
  • Replace the four inline promptui.Select implementations in cmd/auth/logout.go, cmd/auth/token.go, cmd/root/auth.go, and cmd/root/bundle.go with calls to SelectProfile.
  • Add AccountID to Profiles.SearchCaseInsensitive so all pickers support searching by account ID, not just name and host.
  • Extract writeConfigFile helper in libs/databrickscfg/ops.go to consolidate the repeated default-comment / backup / save sequence shared by SaveToProfile and DeleteProfile.

Why

The four profile pickers each duplicated the same prompt setup, searcher wiring, and result extraction. This made it easy for behavior to diverge (e.g., only the logout picker searched by account ID). A single shared helper keeps the UX consistent and reduces the surface area for future changes.

Tests

  • Existing unit and acceptance tests for auth logout, auth token, workspace/account profile selection, and bundle profile resolution continue to pass — the refactor is behavior-preserving.
  • The SelectProfile helper is exercised indirectly through all existing callers.

@eng-dev-ecosystem-bot
Copy link
Collaborator

eng-dev-ecosystem-bot commented Mar 3, 2026

Commit: 51f14b5

Run: 22909775754

Env ❌​FAIL 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 8 7 268 788 10:06
🔄​ aws windows 2 6 7 270 786 10:38
💚​ aws-ucws linux 8 7 365 703 16:31
🔄​ aws-ucws windows 2 7 7 366 701 10:54
💚​ azure linux 2 9 271 786 9:43
💚​ azure windows 2 9 273 784 7:01
❌​ azure-ucws linux 1 2 1 9 366 699 20:15
🔄​ azure-ucws windows 2 1 9 371 697 14:43
💚​ gcp linux 2 9 267 789 7:40
💚​ gcp windows 2 9 269 787 5:14
17 interesting tests: 7 SKIP, 6 RECOVERED, 3 flaky, 1 FAIL
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🔄​ TestAccept 💚​R 🔄​f 💚​R 🔄​f 💚​R 💚​R 🔄​f 🔄​f 💚​R 💚​R
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 💚​R 💚​R 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/resources/postgres_branches/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/update_protected 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/without_branch_id 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestAccept/ssh/connect-serverless-gpu 🙈​s 🙈​s ✅​p 🔄​f 🙈​s 🙈​s 🔄​f 🔄​f 🙈​s 🙈​s
🔄​ TestAccept/ssh/connection 💚​R 🔄​f 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
❌​ TestFetchRepositoryInfoAPI_FromRepo ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p
Top 34 slowest tests (at least 2 minutes):
duration env testname
5:14 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:47 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:44 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:44 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:40 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:26 azure-ucws windows TestAccept/bundle/resources/model_serving_endpoints/basic/DATABRICKS_BUNDLE_ENGINE=terraform
4:23 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:12 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:11 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:11 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:10 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:10 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:02 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:55 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:54 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:49 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:33 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:32 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:23 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:22 aws-ucws linux TestAccept/bundle/resources/model_serving_endpoints/basic/DATABRICKS_BUNDLE_ENGINE=terraform
3:15 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:13 aws-ucws linux TestAccept/ssh/connect-serverless-gpu
3:09 azure-ucws windows TestAccept/bundle/resources/alerts/with_file/DATABRICKS_BUNDLE_ENGINE=terraform
2:54 aws-ucws linux TestAccept/bundle/resources/permissions/jobs/delete_one/cloud/DATABRICKS_BUNDLE_ENGINE=terraform
2:48 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:25 azure-ucws linux TestAccept/bundle/deploy/files/no-snapshot-sync/DATABRICKS_BUNDLE_ENGINE=terraform
2:23 aws-ucws linux TestAccept/bundle/deployment/bind/job/generate-and-bind/DATABRICKS_BUNDLE_ENGINE=direct
2:23 azure-ucws windows TestAccept/bundle/deploy/files/no-snapshot-sync/DATABRICKS_BUNDLE_ENGINE=terraform
2:22 aws-ucws linux TestAccept/bundle/resources/permissions/jobs/delete_one/cloud/DATABRICKS_BUNDLE_ENGINE=direct
2:07 azure-ucws windows TestAccept/bundle/deploy/files/no-snapshot-sync/DATABRICKS_BUNDLE_ENGINE=direct
2:07 aws-ucws linux TestFilerWorkspaceFilesExtensionsStat
2:06 azure-ucws linux TestAccept/bundle/resources/model_serving_endpoints/basic/DATABRICKS_BUNDLE_ENGINE=direct
2:05 azure-ucws windows TestAccept/bundle/deployment/bind/job/generate-and-bind/DATABRICKS_BUNDLE_ENGINE=direct
2:02 aws-ucws windows TestAccept/bundle/resources/permissions/jobs/delete_one/cloud/DATABRICKS_BUNDLE_ENGINE=direct

@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from c6d25f1 to c9512bf Compare March 4, 2026 09:06
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from 8a5d258 to b40887a Compare March 4, 2026 09:45
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from b40887a to 16de011 Compare March 4, 2026 10:25
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from 16de011 to 3116cbb Compare March 5, 2026 12:39
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from 3116cbb to 634b7b9 Compare March 5, 2026 12:52
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from 634b7b9 to 40c98ed Compare March 5, 2026 13:06
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from 40c98ed to 76e7b0e Compare March 5, 2026 13:15
@mihaimitrea-db mihaimitrea-db changed the base branch from main to mihaimitrea-db/stack/auth_logout_profile_picker March 5, 2026 13:30
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_profile_picker branch from c6a2f23 to 3c8e18a Compare March 5, 2026 13:53
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from 76e7b0e to 109b1ca Compare March 5, 2026 13:53
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_profile_picker branch from 3c8e18a to c37cac0 Compare March 5, 2026 14:08
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from 109b1ca to 336ab51 Compare March 5, 2026 14:08
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_profile_picker branch from c37cac0 to 6a3a446 Compare March 5, 2026 14:19
- Use profiler.GetPath() to resolve config path instead of hardcoding platform-specific defaults for the help text.
- Read DATABRICKS_CONFIG_FILE via env.Get(ctx, ...) instead of os.Getenv to respect context-level env overrides.
- Add abort message when user declines the confirmation prompt.
- Guard DeleteProfile against non-existent profiles to avoid creating unnecessary backup files.
- Add TestDeleteProfile_NotFound for the error path.
Cover four scenarios: profile ordering and comments are preserved after deletion, deleting the last non-default profile leaves an empty DEFAULT section, deleting the DEFAULT profile itself clears its keys and restores the default comment, and error paths for non-existent profiles and missing --profile in non-interactive mode.
By default, Authentication related commands. For more information regarding how
authentication for the Databricks CLI and SDKs work please refer to the documentation
linked below.

AWS: https://docs.databricks.com/dev-tools/auth/index.html
Azure: https://learn.microsoft.com/azure/databricks/dev-tools/auth
GCP: https://docs.gcp.databricks.com/dev-tools/auth/index.html

Usage:
  databricks auth [command]

Available Commands:
  describe    Describes the credentials and the source of those credentials, being used by the CLI to authenticate
  env         Get env
  login       Log into a Databricks workspace or account
  profiles    Lists profiles from ~/.databrickscfg
  token       Get authentication token

Flags:
      --account-id string              Databricks Account ID
      --experimental-is-unified-host   Flag to indicate if the host is a unified host
  -h, --help                           help for auth
      --host string                    Databricks Host
      --workspace-id string            Databricks Workspace ID

Global Flags:
      --debug            enable debug logging
  -o, --output type      output type: text or json (default text)
  -p, --profile string   ~/.databrickscfg profile
  -t, --target string    bundle target to use (if applicable)

Use "databricks auth [command] --help" for more information about a command. now only clears cached OAuth
tokens without removing the profile from ~/.databrickscfg. Pass
--delete to also remove the profile entry from the config file.
Existing acceptance tests that verify profile deletion now use --delete
since profile removal is opt-in. Two new acceptance tests verify token-only
logout: one for a unique host (both cache entries cleared) and one for a
shared host (host-keyed token preserved).
Replace manual strings.TrimRight(host, /) with the SDK's
config.Config.CanonicalHostName(), which handles scheme
normalization, trailing slashes, and empty hosts consistently
with how the SDK itself computes token cache keys.
- Make Long description static to avoid calling logger and GetPath at
  command construction time before the logger is initialized.
- Remove empty test.toml files from acceptance tests.
- Add \n to error-case titles so errors appear on a separate line.
- Use .tokens | keys in jq queries for token cache to reduce verbosity.
- Switch test profiles from PAT to auth_type=databricks-cli (U2M) so
  token cache tests exercise a realistic OAuth logout flow.
- Add AuthType field to profile.Profile to detect non-U2M profiles;
  skip token cache cleanup and adjust success message accordingly.
- Add delete-m2m-profiles acceptance test covering PAT profile logout
  with and without --delete.
- Fix DeleteProfile to clear DEFAULT section keys instead of
  deleting and recreating it, preserving its position in the file.
- Rename isU2MProfile to isCreatedByLogin to accurately reflect
  that the check is specific to profiles created by .
- Tighten success and error messages: drop "Successfully", add
  actionable suggestions (e.g. "Use --delete to also remove it"),
  and include retry guidance on partial failures.
- Return errors instead of logging on DeleteProfile failure so
  callers see a non-zero exit code.
- Fix token-only acceptance test: use OIDC-style cache key
  (host/oidc/accounts/<id>) for account profiles so both token
  cache entries are correctly cleaned up.
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from 8e3d5e7 to ed5be7c Compare March 9, 2026 12:41
When --profile is not specified in an interactive terminal, show a
searchable prompt listing all configured profiles. Profiles are sorted
alphabetically and displayed with their host or account ID. The picker
supports fuzzy search by name, host, or account ID.
Document the four interaction modes (explicit profile, interactive
picker, non-interactive error, and --force) in the command's long
help text.
…ckers

Four places built nearly identical promptui.Select prompts for
interactive profile selection (auth logout, auth token, root auth,
root bundle). Extract a reusable profile.SelectProfile function that
takes a declarative SelectConfig with label, profiles, and template
strings.

Also: add AccountID to Profiles.SearchCaseInsensitive so all pickers
support searching by account ID, and remove the redundant
not-found guard in DeleteProfile (ini.DeleteSection is already a
no-op for missing sections).
Extract writeConfigFile helper to consolidate the repeated
default-comment, backup, and save sequence shared by SaveToProfile
and DeleteProfile.

Also switch auth login from os.Getenv to env.Get(ctx, ...) for
DATABRICKS_CONFIG_FILE so it respects context-level env overrides,
consistent with the rest of the codebase.
- Restore StartInSearchMode for logout picker so profiles with 6+
  entries auto-activate search, matching the previous behavior.
- Improve empty-profiles error to suggest running 'databricks auth
  login' instead of the generic "no profiles to select from".
@mihaimitrea-db mihaimitrea-db force-pushed the mihaimitrea-db/stack/auth_logout_deduplication branch from ed5be7c to 51f14b5 Compare March 10, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants