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
15 changes: 13 additions & 2 deletions cli/azd/cmd/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -2128,7 +2128,7 @@ func selectDistinctExtension(
return matches[0], nil
}

if global.NoPrompt {
if global != nil && global.NoPrompt {
return nil, &internal.ErrorWithSuggestion{
Err: fmt.Errorf("the %s extension was found in multiple sources.", extensionId),
Suggestion: "Specify the extension source using the --source flag.",
Expand All @@ -2150,7 +2150,8 @@ func selectDistinctExtension(
"The %s extension was found in multiple sources.\nSelect the source to continue",
output.WithHighLightFormat(extensionId),
),
Choices: sourceChoices,
Choices: sourceChoices,
SelectedIndex: defaultExtensionSourceIndex(matches),
})

sourceResponseIndex, err := selectSource.Ask(ctx)
Expand All @@ -2163,6 +2164,16 @@ func selectDistinctExtension(
return matches[*sourceResponseIndex], nil
}

func defaultExtensionSourceIndex(matches []*extensions.ExtensionMetadata) *int {
for i, ext := range matches {
if strings.EqualFold(ext.Source, "azd") {
return new(i)
}
}

return new(0)
}

// checkNamespaceConflict checks if the given namespace conflicts with any installed extension.
// Two namespaces conflict if one is a prefix of the other (e.g., "ai" and "ai.agent").
func checkNamespaceConflict(
Expand Down
43 changes: 43 additions & 0 deletions cli/azd/cmd/extension_coverage3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,49 @@ func Test_SelectDistinctExtension_MultipleNoPrompt(t *testing.T) {
assert.Contains(t, err.Error(), "multiple sources")
}

func Test_DefaultExtensionSourceIndex(t *testing.T) {
t.Parallel()

tests := []struct {
name string
matches []*extensions.ExtensionMetadata
want int
}{
{
name: "DefaultsToAzdSourceWhenPresent",
matches: []*extensions.ExtensionMetadata{
{Source: "contoso"},
{Source: "azd"},
},
want: 1,
},
{
name: "DefaultsToFirstSourceWhenAzdMissing",
matches: []*extensions.ExtensionMetadata{
{Source: "contoso"},
{Source: "fabrikam"},
},
want: 0,
},
{
name: "MatchesAzdSourceCaseInsensitively",
matches: []*extensions.ExtensionMetadata{
{Source: "contoso"},
{Source: "AZD"},
},
want: 1,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

require.Equal(t, tt.want, *defaultExtensionSourceIndex(tt.matches))
})
}
}

// --- namespacesConflict Tests (additional paths) ---

func Test_NamespacesConflict_SameNamespace(t *testing.T) {
Expand Down
16 changes: 12 additions & 4 deletions cli/azd/cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -1160,12 +1160,20 @@ func (i *initAction) initializeExtensions(ctx context.Context, azdCtx *azdcontex
return fmt.Errorf("extension %s not found", extensionId)
}

if len(extensionMatches) > 1 {
extensionMetadata, err := selectDistinctExtension(
ctx,
i.console,
extensionId,
extensionMatches,
i.flags.global,
)
if err != nil {
i.console.StopSpinner(ctx, stepMessage, input.StepFailed)
return fmt.Errorf("extension %s found in multiple sources, specify exact source", extensionId)
return err
}
if len(extensionMatches) > 1 {
i.console.ShowSpinner(ctx, stepMessage, input.Step)
}

extensionMetadata := extensionMatches[0]

extensionVersion, err := i.extensionsManager.Install(ctx, extensionMetadata, installConstraint)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cli/azd/pkg/environment/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ func (m *manager) ensureValidEnvironmentName(ctx context.Context, spec *Spec) er

for !IsValidEnvironmentName(spec.Name) {
userInput, err := m.console.Prompt(ctx, input.ConsoleOptions{
Message: "Enter a unique environment name:",
Message: "Enter a unique environment name",
Help: heredoc.Doc(`
A unique string that can be used to differentiate copies of your application in Azure.

Expand Down
Loading