feat: add tenant picker before subscription prompt for multi-tenant users#8083
feat: add tenant picker before subscription prompt for multi-tenant users#8083
Conversation
…sers When users have access to multiple Azure tenants, the subscription list now shows a tenant selection step first to scope down the list. This addresses the UX issue where users with many tenants see an overwhelming list of subscriptions from all tenants. Key behaviors: - Single tenant: skipped, goes straight to subscription selection - Multiple tenants: shows picker with display names + "All tenants" option - AZURE_TENANT_ID env var: pre-filters subscriptions in both prompt and no-prompt modes - No-prompt mode: tenant picker skipped but env var filtering still applies Both PromptSubscription paths (DefaultPrompter and promptService) are updated so extensions get the tenant picker automatically via gRPC. Fixes #2993 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a tenant-selection step ahead of subscription selection to improve UX for multi-tenant users by scoping the subscription list to a chosen tenant (with an “All tenants” escape hatch), while also introducing shared helper logic and tenant display-name lookup.
Changes:
- Introduces
tenant_helper.goto extract unique tenants, filter subscriptions by tenant, and drive the tenant picker UI. - Updates both
DefaultPrompter.PromptSubscriptionandpromptService.PromptSubscriptionto apply tenant filtering (includingAZURE_TENANT_ID) and optionally prompt for tenant selection. - Extends the account/subscription manager surface area to provide tenant display names (via
ListTenants) and updates mocks/tests accordingly.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| cli/azd/test/mocks/mockaccount/mock_subscriptions.go | Extends subscription manager mock with GetTenantDisplayNames. |
| cli/azd/test/mocks/mockaccount/mock_manager.go | Extends account manager mock with GetTenantDisplayNames. |
| cli/azd/pkg/prompt/tenant_helper.go | New helper for tenant extraction, filtering, env var handling, and tenant selection prompt. |
| cli/azd/pkg/prompt/tenant_helper_test.go | New unit/E2E-style tests covering tenant extraction/filtering and multi-tenant prompt flows. |
| cli/azd/pkg/prompt/prompter.go | Adds tenant pre-step to PromptSubscription and factors out subscription option formatting. |
| cli/azd/pkg/prompt/prompter_test.go | Updates tests to cover the extracted formatSubscriptionOptions helper. |
| cli/azd/pkg/prompt/prompter_extra_test.go | Adjusts prompt tests for new tenant behavior and helper extraction. |
| cli/azd/pkg/prompt/prompt_service.go | Adds tenant pre-step to prompt service subscription selection and adds display-name lookup hook. |
| cli/azd/pkg/account/subscriptions_manager.go | Implements GetTenantDisplayNames() via ListTenants. |
| cli/azd/pkg/account/manager.go | Adds GetTenantDisplayNames to the Manager interface and delegates implementation. |
- Fix loop variable pointer bug in subscription slice building - Clear loading message to avoid redundant spinner with pre-loaded data - Update filterByTenantEnvVar comment to accurately reflect fallback behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Skip spinner in PromptCustomResource when LoadingMessage is empty - Remove unused preSelectedTenantId parameter from promptTenantSelection - Update PR description to reflect graceful fallback behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add SkipLoadingSpinner field to SelectOptions for reliable spinner skip - Extract shared promptAndFilterByTenant function to eliminate duplication Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Make TenantInfo unexported (tenantInfo) to reduce public API surface - Update extractUniqueTenants comment to document TenantId fallback - Add test for SkipLoadingSpinner path in PromptCustomResource Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Guard mock GetTenantDisplayNames against nil panic - Skip subscriptions with empty tenant IDs - Add deterministic sort tie-breaker by tenant ID Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Hoist isDemoModeEnabled() call outside subscription format loop - Add nil guard for getTenantNames provider - Skip empty tenant IDs in mock GetTenantDisplayNames Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Wrap GetSubscriptions error with context in promptService - Add no-prompt mode test verifying tenant picker is skipped and env var filtering works Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use append-based filtering instead of clone+delete for efficiency - Fix test comment to accurately describe no-prompt behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
Summary
When users have access to multiple Azure tenants, the subscription prompt now shows a tenant selection step first to scope down the list. This addresses the UX issue where users with many tenants see an overwhelming list of subscriptions from all tenants mixed together.
Fixes #2993
Key Behaviors
AZURE_TENANT_IDenv var: Pre-filters subscriptions in both prompt and no-prompt modes. If the env var is set but no subscriptions match (e.g. stale tenant ID), the filter is a no-op and all subscriptions are shown to avoid blocking the user.Changes
pkg/prompt/tenant_helper.gopkg/prompt/tenant_helper_test.gopkg/account/manager.goGetTenantDisplayNamestoManagerinterfacepkg/account/subscriptions_manager.goGetTenantDisplayNames()method (delegates toListTenantsAPI)pkg/prompt/prompter.goDefaultPrompter.PromptSubscription; extractedformatSubscriptionOptionshelperpkg/prompt/prompt_service.gopromptService.PromptSubscriptionwith spinner/prompt separation; addedSkipLoadingSpinneroption toSelectOptionsandPromptCustomResourceDesign Decisions
ListTenants()API only when >1 tenant is detected (avoids unnecessary call for single-tenant users). Falls back to tenant IDs if the call fails.PromptCustomResourceskips its inner spinner whenSkipLoadingSpinneris set to true on theSelectOptions.AZURE_TENANT_IDfiltering is best-effort: if the env var doesn't match any available tenant, all subscriptions are shown rather than erroring out.