Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions cli/azd/pkg/prompt/prompt_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (
"context"
"fmt"
"io"
"os"
"slices"
"strconv"
"strings"

"dario.cat/mergo"
Expand All @@ -28,6 +30,28 @@ var (
ErrNoResourceSelected = fmt.Errorf("no resource selected")
)

func isDemoModeEnabled() bool {
v, err := strconv.ParseBool(os.Getenv("AZD_DEMO_MODE"))
return err == nil && v
}

func formatSubscriptionDisplayName(subscription *account.Subscription, hideId bool) string {
if hideId {
return subscription.Name
}

return fmt.Sprintf("%s %s", subscription.Name, output.WithGrayFormat("(%s)", subscription.Id))
}

func formatAutoSelectedSubscriptionMessage(subscription *account.Subscription, hideId bool) string {
message := fmt.Sprintf("Auto-selected subscription: %s", subscription.Name)
if hideId {
return message
}

return fmt.Sprintf("%s (%s)", message, subscription.Id)
}

// ResourceOptions contains options for prompting the user to select a resource.
type ResourceOptions struct {
// ResourceType is the type of resource to select.
Expand Down Expand Up @@ -222,6 +246,8 @@ func (ps *promptService) PromptSubscription(
}
}

hideId := isDemoModeEnabled()

// Handle --no-prompt mode
if ps.globalOptions.NoPrompt {
// Load subscriptions for both default lookup and auto-selection
Expand All @@ -238,6 +264,13 @@ func (ps *promptService) PromptSubscription(
}
}

if hideId {
return nil, fmt.Errorf(
"default subscription not found. " +
"Update your default subscription using " +
"'azd config set defaults.subscription <subscription-id>'")
}

return nil, fmt.Errorf(
"default subscription '%s' not found. "+
"Update your default subscription using "+
Expand All @@ -254,9 +287,7 @@ func (ps *promptService) PromptSubscription(
"and that your account has one or more active subscriptions. " +
"If needed, run 'azd auth login' to sign in.")
case 1:
ps.console.Message(ctx, fmt.Sprintf(
"Auto-selected subscription: %s (%s)",
subscriptionList[0].Name, subscriptionList[0].Id))
ps.console.Message(ctx, formatAutoSelectedSubscriptionMessage(&subscriptionList[0], hideId))
return &subscriptionList[0], nil
default:
return nil, fmt.Errorf(
Expand All @@ -281,7 +312,7 @@ func (ps *promptService) PromptSubscription(
return subscriptions, nil
},
DisplayResource: func(subscription *account.Subscription) (string, error) {
return fmt.Sprintf("%s %s", subscription.Name, output.WithGrayFormat("(%s)", subscription.Id)), nil
return formatSubscriptionDisplayName(subscription, hideId), nil
},
Selected: func(subscription *account.Subscription) bool {
return strings.EqualFold(subscription.Id, defaultSubscriptionId)
Expand Down
77 changes: 77 additions & 0 deletions cli/azd/pkg/prompt/prompt_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package prompt

import (
"context"
"strings"
"testing"

"github.com/azure/azure-dev/cli/azd/internal"
Expand Down Expand Up @@ -166,3 +167,79 @@ func Test_PromptService_PromptSubscription_NoPrompt_AutoSelect(t *testing.T) {
})
}
}

func TestFormatSubscriptionDisplayName_DemoModeHidesId(t *testing.T) {
displayName := formatSubscriptionDisplayName(&account.Subscription{
Id: "/subscriptions/sub-1",
Name: "Subscription 1",
}, true)

require.Equal(t, "Subscription 1", displayName)
}

func TestPromptSubscription_NoPrompt_AutoSelect_DemoModeRedactsOutput(t *testing.T) {
t.Setenv("AZD_DEMO_MODE", "true")

ucm := newInMemoryUserConfigManager(nil)
authManager := &mockauth.MockAuthManager{}
subscriptionManager := &mockaccount.MockSubscriptionManager{}
resourceService := &mockazapi.MockResourceService{}
mockConsole := mockinput.NewMockConsole()
mockConsole.SetNoPromptMode(true)

subscriptionManager.
On("GetSubscriptions", mock.Anything).
Return([]account.Subscription{
{Id: "sub-1", TenantId: "tenant-1", Name: "My Only Sub"},
}, nil)

ps := NewPromptService(
authManager,
mockConsole,
ucm,
subscriptionManager,
resourceService,
&internal.GlobalCommandOptions{NoPrompt: true},
)

result, err := ps.PromptSubscription(context.Background(), nil)
require.NoError(t, err)
require.Equal(t, "sub-1", result.Id)
require.Len(t, mockConsole.Output(), 1)
require.Equal(t, "Auto-selected subscription: My Only Sub", mockConsole.Output()[0])
}

func TestPromptSubscription_NoPrompt_DefaultNotFound_DemoModeRedactsId(t *testing.T) {
t.Setenv("AZD_DEMO_MODE", "true")

cfg := config.NewEmptyConfig()
err := cfg.Set("defaults.subscription", "sub-secret")
require.NoError(t, err)

ucm := newInMemoryUserConfigManager(cfg)
authManager := &mockauth.MockAuthManager{}
subscriptionManager := &mockaccount.MockSubscriptionManager{}
resourceService := &mockazapi.MockResourceService{}
mockConsole := mockinput.NewMockConsole()
mockConsole.SetNoPromptMode(true)

subscriptionManager.
On("GetSubscriptions", mock.Anything).
Return([]account.Subscription{
{Id: "sub-1", TenantId: "tenant-1", Name: "Sub 1"},
}, nil)

ps := NewPromptService(
authManager,
mockConsole,
ucm,
subscriptionManager,
resourceService,
&internal.GlobalCommandOptions{NoPrompt: true},
)

_, err = ps.PromptSubscription(context.Background(), nil)
require.Error(t, err)
require.ErrorContains(t, err, "default subscription not found")
require.False(t, strings.Contains(err.Error(), "sub-secret"))
}
Loading