From 1f53545f761dfcfc4d64f549379baa6002450e9d Mon Sep 17 00:00:00 2001 From: Victor Vazquez Date: Sat, 1 Feb 2025 22:03:53 +0000 Subject: [PATCH 1/5] Support default location override from bicep allowed tag or azd metadata --- cli/azd/cmd/env.go | 5 ++- cli/azd/cmd/up.go | 3 +- cli/azd/internal/cmd/add/add_preview.go | 3 +- cli/azd/internal/cmd/add/add_select_ai.go | 3 +- cli/azd/pkg/azure/arm_template.go | 1 + cli/azd/pkg/azureutil/location.go | 11 +++++ .../provisioning/bicep/bicep_provider.go | 43 +++++++++++++++++-- .../pkg/infra/provisioning/bicep/prompt.go | 3 +- cli/azd/pkg/infra/provisioning/manager.go | 12 +++++- .../terraform/terraform_provider.go | 2 +- .../infra/provisioning/test/test_provider.go | 3 +- cli/azd/pkg/prompt/prompter.go | 10 ++++- 12 files changed, 81 insertions(+), 18 deletions(-) diff --git a/cli/azd/cmd/env.go b/cli/azd/cmd/env.go index fc108b7d884..9d80f16ee92 100644 --- a/cli/azd/cmd/env.go +++ b/cli/azd/cmd/env.go @@ -307,7 +307,8 @@ func (e *envSetSecretAction) Run(ctx context.Context) (*actions.ActionResult, er } if willCreateNewKvAccount { - location, err := e.prompter.PromptLocation(ctx, subId, "Select the location to create the Key Vault", nil) + location, err := e.prompter.PromptLocation( + ctx, subId, "Select the location to create the Key Vault", nil, nil) if err != nil { return nil, fmt.Errorf("prompting for Key Vault location: %w", err) } @@ -788,7 +789,7 @@ func (ef *envRefreshAction) Run(ctx context.Context) (*actions.ActionResult, err if errors.Is(err, bicep.ErrEnsureEnvPreReqBicepCompileFailed) { // If bicep is not available, we continue to prompt for subscription and location unfiltered err = provisioning.EnsureSubscriptionAndLocation(ctx, ef.envManager, ef.env, ef.prompters, - func(_ account.Location) bool { return true }) + provisioning.EnsureSubscriptionAndLocationOptions{}) if err != nil { return nil, err } diff --git a/cli/azd/cmd/up.go b/cli/azd/cmd/up.go index b11c4bcff29..988e7be0173 100644 --- a/cli/azd/cmd/up.go +++ b/cli/azd/cmd/up.go @@ -116,7 +116,8 @@ func (u *upAction) Run(ctx context.Context) (*actions.ActionResult, error) { err = u.provisioningManager.Initialize(ctx, u.projectConfig.Path, infra.Options) if errors.Is(err, bicep.ErrEnsureEnvPreReqBicepCompileFailed) { // If bicep is not available, we continue to prompt for subscription and location unfiltered - err = provisioning.EnsureSubscriptionAndLocation(ctx, u.envManager, u.env, u.prompters, nil) + err = provisioning.EnsureSubscriptionAndLocation( + ctx, u.envManager, u.env, u.prompters, provisioning.EnsureSubscriptionAndLocationOptions{}) if err != nil { return nil, err } diff --git a/cli/azd/internal/cmd/add/add_preview.go b/cli/azd/internal/cmd/add/add_preview.go index 4433d166894..62f95bfa6c8 100644 --- a/cli/azd/internal/cmd/add/add_preview.go +++ b/cli/azd/internal/cmd/add/add_preview.go @@ -78,7 +78,8 @@ func (a *AddAction) previewProvision( usedBy []string, ) error { a.console.ShowSpinner(ctx, "Previewing changes....", input.Step) - err := provisioning.EnsureSubscriptionAndLocation(ctx, a.envManager, a.env, a.prompter, nil) + err := provisioning.EnsureSubscriptionAndLocation( + ctx, a.envManager, a.env, a.prompter, provisioning.EnsureSubscriptionAndLocationOptions{}) if err != nil { return err } diff --git a/cli/azd/internal/cmd/add/add_select_ai.go b/cli/azd/internal/cmd/add/add_select_ai.go index 600316d5126..2a276f89304 100644 --- a/cli/azd/internal/cmd/add/add_select_ai.go +++ b/cli/azd/internal/cmd/add/add_select_ai.go @@ -41,7 +41,8 @@ func (a *AddAction) selectOpenAi( var allModels []ModelList for { - err = provisioning.EnsureSubscriptionAndLocation(ctx, a.envManager, a.env, a.prompter, nil) + err = provisioning.EnsureSubscriptionAndLocation( + ctx, a.envManager, a.env, a.prompter, provisioning.EnsureSubscriptionAndLocationOptions{}) if err != nil { return nil, err } diff --git a/cli/azd/pkg/azure/arm_template.go b/cli/azd/pkg/azure/arm_template.go index ca180b2a643..8a931697e70 100644 --- a/cli/azd/pkg/azure/arm_template.go +++ b/cli/azd/pkg/azure/arm_template.go @@ -143,6 +143,7 @@ type AzdMetadata struct { Type *AzdMetadataType `json:"type,omitempty"` AutoGenerateConfig *AutoGenInput `json:"config,omitempty"` DefaultValueExpr *string `json:"defaultValueExpr,omitempty"` + DefaultLocation *string `json:"defaultLocation,omitempty"` } // Description returns the value of the "Description" string metadata for this parameter or empty if it can not be found. diff --git a/cli/azd/pkg/azureutil/location.go b/cli/azd/pkg/azureutil/location.go index 44677f6c263..28aa3aafdf9 100644 --- a/cli/azd/pkg/azureutil/location.go +++ b/cli/azd/pkg/azureutil/location.go @@ -25,6 +25,7 @@ func PromptLocationWithFilter( console input.Console, accountManager account.Manager, shouldDisplay func(account.Location) bool, + defaultSelectedLocation *string, ) (string, error) { allLocations, err := accountManager.GetLocations(ctx, subscriptionId) if err != nil { @@ -47,10 +48,20 @@ func PromptLocationWithFilter( strings.ToLower(a.RegionalDisplayName), strings.ToLower(b.RegionalDisplayName)) }) + // Default location selection. + // The order of precedence for selecting the default location is as follows: + // 1. The location set in the system environment. (AZURE_LOCATION) -> CI/CD strategy + // 2. Parameter passed to the function. (defaultSelectedLocation != nil) + // 3. The location set in the azd config. -> CI/CD strategy + // Allow the environment variable `AZURE_LOCATION` to control the default value for the location // selection. defaultLocation := os.Getenv(environment.LocationEnvVarName) + if defaultLocation == "" && defaultSelectedLocation != nil { + defaultLocation = *defaultSelectedLocation + } + // If no location is set in the process environment, see what the azd config default is. if defaultLocation == "" { defaultLocation = accountManager.GetDefaultLocationName(ctx) diff --git a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go index bdad2c8f672..a404987f952 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go +++ b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go @@ -120,7 +120,8 @@ func (p *BicepProvider) EnsureEnv(ctx context.Context) error { // for .bicepparam, we first prompt for environment values before calling compiling bicepparam file // which can reference these values if isBicepParamFile(modulePath) { - if err := provisioning.EnsureSubscriptionAndLocation(ctx, p.envManager, p.env, p.prompters, nil); err != nil { + if err := provisioning.EnsureSubscriptionAndLocation( + ctx, p.envManager, p.env, p.prompters, provisioning.EnsureSubscriptionAndLocationOptions{}); err != nil { return err } } @@ -130,10 +131,12 @@ func (p *BicepProvider) EnsureEnv(ctx context.Context) error { return fmt.Errorf("%w%w", ErrEnsureEnvPreReqBicepCompileFailed, compileErr) } - // for .bicep, azd must load a parameters.json file and create the ArmParameters + // for .bicep, azd must load a parameters.json file and create the ArmParameters so we know if the are filters + // to apply for location (using the allowedValues or the location azd metadata) if isBicepFile(modulePath) { + locationParam, locationParamDefined := compileResult.Template.Parameters["location"] var filterLocation = func(loc account.Location) bool { - if locationParam, defined := compileResult.Template.Parameters["location"]; defined { + if locationParamDefined { if locationParam.AllowedValues != nil { return slices.IndexFunc(*locationParam.AllowedValues, func(allowedValue any) bool { allowedValueString, goodCast := allowedValue.(string) @@ -143,8 +146,16 @@ func (p *BicepProvider) EnsureEnv(ctx context.Context) error { } return true } + var defaultLocationToSelect *string + if locationParamDefined { + defaultLocationToSelect = defaultLocationToSelectFn(locationParam) + } - err := provisioning.EnsureSubscriptionAndLocation(ctx, p.envManager, p.env, p.prompters, filterLocation) + err := provisioning.EnsureSubscriptionAndLocation( + ctx, p.envManager, p.env, p.prompters, provisioning.EnsureSubscriptionAndLocationOptions{ + LocationFiler: filterLocation, + SelectDefaultLocation: defaultLocationToSelect, + }) if err != nil { return err } @@ -176,6 +187,30 @@ func (p *BicepProvider) EnsureEnv(ctx context.Context) error { return nil } +// defaultLocationToSelectFn resolves if there is an intention from a location parameter to use a default location. +// If the parameter has the @allowedValues set, it will return the first value from the array as the default. +// If the parameter has the location azd metadata, it will check if there is configuration to set a default location. +// If both @allowedValues and azd location metadata config are set, the metadata config will take precedence. +// If nothing is set, it will return nil. +func defaultLocationToSelectFn(locationParam azure.ArmTemplateParameterDefinition) *string { + azdMetadata, has := locationParam.AzdMetadata() + if has && + azdMetadata.Type != nil && *azdMetadata.Type == azure.AzdMetadataTypeLocation && + azdMetadata.DefaultLocation != nil { + // Metadata using location type and a default location. This is the highest priority. + return azdMetadata.DefaultLocation + } + + if locationParam.AllowedValues != nil { + firstOption, castOk := (*locationParam.AllowedValues)[0].(string) + // if cast doesn't work, we don't have a default location + if castOk { + return &firstOption + } + } + return nil +} + func (p *BicepProvider) LastDeployment(ctx context.Context) (*azapi.ResourceDeployment, error) { modulePath := p.modulePath() compileResult, err := p.compileBicep(ctx, modulePath) diff --git a/cli/azd/pkg/infra/provisioning/bicep/prompt.go b/cli/azd/pkg/infra/provisioning/bicep/prompt.go index 1b7f23c7661..7f866adbf89 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/prompt.go +++ b/cli/azd/pkg/infra/provisioning/bicep/prompt.go @@ -105,8 +105,7 @@ func (p *BicepProvider) promptForParameter( s, ok := v.(string) return ok && loc.Name == s }) != -1 - }, - ) + }, defaultLocationToSelectFn(param)) if err != nil { return nil, err } diff --git a/cli/azd/pkg/infra/provisioning/manager.go b/cli/azd/pkg/infra/provisioning/manager.go index 5979aac9a71..953e145725c 100644 --- a/cli/azd/pkg/infra/provisioning/manager.go +++ b/cli/azd/pkg/infra/provisioning/manager.go @@ -332,6 +332,13 @@ func (m *Manager) UpdateEnvironment( return nil } +type EnsureSubscriptionAndLocationOptions struct { + // LocationFilterPredicate is a function to filter the locations being displayed if prompting the user for the location. + LocationFiler prompt.LocationFilterPredicate + // SelectDefaultLocation is the default location that azd mark as selected when prompting the user for the location. + SelectDefaultLocation *string +} + // EnsureSubscriptionAndLocation ensures that that that subscription (AZURE_SUBSCRIPTION_ID) and location (AZURE_LOCATION) // variables are set in the environment, prompting the user for the values if they do not exist. // locationFilter, when non-nil, filters the locations being displayed. @@ -340,7 +347,7 @@ func EnsureSubscriptionAndLocation( envManager environment.Manager, env *environment.Environment, prompter prompt.Prompter, - locationFiler prompt.LocationFilterPredicate, + options EnsureSubscriptionAndLocationOptions, ) error { subId := env.GetSubscriptionId() if subId == "" { @@ -366,7 +373,8 @@ func EnsureSubscriptionAndLocation( ctx, env.GetSubscriptionId(), "Select an Azure location to use:", - locationFiler, + options.LocationFiler, + options.SelectDefaultLocation, ) if err != nil { return err diff --git a/cli/azd/pkg/infra/provisioning/terraform/terraform_provider.go b/cli/azd/pkg/infra/provisioning/terraform/terraform_provider.go index 3dc9f44b574..2757cb95d7d 100644 --- a/cli/azd/pkg/infra/provisioning/terraform/terraform_provider.go +++ b/cli/azd/pkg/infra/provisioning/terraform/terraform_provider.go @@ -130,7 +130,7 @@ func (t *TerraformProvider) EnsureEnv(ctx context.Context) error { t.envManager, t.env, t.prompters, - nil, + provisioning.EnsureSubscriptionAndLocationOptions{}, ) } diff --git a/cli/azd/pkg/infra/provisioning/test/test_provider.go b/cli/azd/pkg/infra/provisioning/test/test_provider.go index edc08af66ee..6fc5a29933b 100644 --- a/cli/azd/pkg/infra/provisioning/test/test_provider.go +++ b/cli/azd/pkg/infra/provisioning/test/test_provider.go @@ -10,7 +10,6 @@ import ( "context" "errors" - "github.com/azure/azure-dev/cli/azd/pkg/account" "github.com/azure/azure-dev/cli/azd/pkg/environment" "github.com/azure/azure-dev/cli/azd/pkg/infra/provisioning" "github.com/azure/azure-dev/cli/azd/pkg/input" @@ -54,7 +53,7 @@ func (t *TestProvider) EnsureEnv(ctx context.Context) error { t.envManager, t.env, t.prompters, - func(_ account.Location) bool { return true }, + provisioning.EnsureSubscriptionAndLocationOptions{}, ) } diff --git a/cli/azd/pkg/prompt/prompter.go b/cli/azd/pkg/prompt/prompter.go index f78d554eba9..e6a80a5937b 100644 --- a/cli/azd/pkg/prompt/prompter.go +++ b/cli/azd/pkg/prompt/prompter.go @@ -28,7 +28,12 @@ type LocationFilterPredicate func(loc account.Location) bool type Prompter interface { PromptSubscription(ctx context.Context, msg string) (subscriptionId string, err error) - PromptLocation(ctx context.Context, subId string, msg string, filter LocationFilterPredicate) (string, error) + PromptLocation( + ctx context.Context, + subId string, + msg string, + filter LocationFilterPredicate, + defaultLocation *string) (string, error) PromptResourceGroup(ctx context.Context) (string, error) PromptResourceGroupFrom( ctx context.Context, subscriptionId string, location string, options PromptResourceGroupFromOptions) (string, error) @@ -101,8 +106,9 @@ func (p *DefaultPrompter) PromptLocation( subId string, msg string, filter LocationFilterPredicate, + defaultLocation *string, ) (string, error) { - loc, err := azureutil.PromptLocationWithFilter(ctx, subId, msg, "", p.console, p.accountManager, filter) + loc, err := azureutil.PromptLocationWithFilter(ctx, subId, msg, "", p.console, p.accountManager, filter, defaultLocation) if err != nil { return "", err } From 5ed87895eb631d05cfa5cdfce0091adda4d648a7 Mon Sep 17 00:00:00 2001 From: Victor Vazquez Date: Sat, 1 Feb 2025 22:09:09 +0000 Subject: [PATCH 2/5] re-use filter location param logic --- .../provisioning/bicep/bicep_provider.go | 21 +++++++++++-------- .../pkg/infra/provisioning/bicep/prompt.go | 10 +-------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go index a404987f952..a763654f06a 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go +++ b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go @@ -136,15 +136,7 @@ func (p *BicepProvider) EnsureEnv(ctx context.Context) error { if isBicepFile(modulePath) { locationParam, locationParamDefined := compileResult.Template.Parameters["location"] var filterLocation = func(loc account.Location) bool { - if locationParamDefined { - if locationParam.AllowedValues != nil { - return slices.IndexFunc(*locationParam.AllowedValues, func(allowedValue any) bool { - allowedValueString, goodCast := allowedValue.(string) - return goodCast && loc.Name == allowedValueString - }) != -1 - } - } - return true + return locationParameterFilterImpl(locationParam, loc) } var defaultLocationToSelect *string if locationParamDefined { @@ -187,6 +179,17 @@ func (p *BicepProvider) EnsureEnv(ctx context.Context) error { return nil } +func locationParameterFilterImpl(param azure.ArmTemplateParameterDefinition, location account.Location) bool { + if param.AllowedValues == nil { + return true + } + + return slices.IndexFunc(*param.AllowedValues, func(v any) bool { + s, ok := v.(string) + return ok && location.Name == s + }) != -1 +} + // defaultLocationToSelectFn resolves if there is an intention from a location parameter to use a default location. // If the parameter has the @allowedValues set, it will return the first value from the array as the default. // If the parameter has the location azd metadata, it will check if there is configuration to set a default location. diff --git a/cli/azd/pkg/infra/provisioning/bicep/prompt.go b/cli/azd/pkg/infra/provisioning/bicep/prompt.go index 7f866adbf89..9f60f530ad4 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/prompt.go +++ b/cli/azd/pkg/infra/provisioning/bicep/prompt.go @@ -7,7 +7,6 @@ import ( "context" "encoding/json" "fmt" - "slices" "strconv" "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" @@ -97,14 +96,7 @@ func (p *BicepProvider) promptForParameter( *azdMetadata.Type == azure.AzdMetadataTypeLocation { location, err := p.prompters.PromptLocation(ctx, p.env.GetSubscriptionId(), msg, func(loc account.Location) bool { - if param.AllowedValues == nil { - return true - } - - return slices.IndexFunc(*param.AllowedValues, func(v any) bool { - s, ok := v.(string) - return ok && loc.Name == s - }) != -1 + return locationParameterFilterImpl(param, loc) }, defaultLocationToSelectFn(param)) if err != nil { return nil, err From 0a5b4638beaf0fd2abcd0aa08edbaf965eaf1f16 Mon Sep 17 00:00:00 2001 From: Victor Vazquez Date: Mon, 3 Feb 2025 22:34:14 +0000 Subject: [PATCH 3/5] rename to default --- cli/azd/pkg/azure/arm_template.go | 2 +- cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/azd/pkg/azure/arm_template.go b/cli/azd/pkg/azure/arm_template.go index 8a931697e70..ce97b814ebe 100644 --- a/cli/azd/pkg/azure/arm_template.go +++ b/cli/azd/pkg/azure/arm_template.go @@ -143,7 +143,7 @@ type AzdMetadata struct { Type *AzdMetadataType `json:"type,omitempty"` AutoGenerateConfig *AutoGenInput `json:"config,omitempty"` DefaultValueExpr *string `json:"defaultValueExpr,omitempty"` - DefaultLocation *string `json:"defaultLocation,omitempty"` + Default *string `json:"default,omitempty"` } // Description returns the value of the "Description" string metadata for this parameter or empty if it can not be found. diff --git a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go index a763654f06a..ea393b1ab9b 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go +++ b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go @@ -199,9 +199,9 @@ func defaultLocationToSelectFn(locationParam azure.ArmTemplateParameterDefinitio azdMetadata, has := locationParam.AzdMetadata() if has && azdMetadata.Type != nil && *azdMetadata.Type == azure.AzdMetadataTypeLocation && - azdMetadata.DefaultLocation != nil { + azdMetadata.Default != nil { // Metadata using location type and a default location. This is the highest priority. - return azdMetadata.DefaultLocation + return azdMetadata.Default } if locationParam.AllowedValues != nil { From e8f74f7adae0de5f23acd13eb33a7487f3ca47a7 Mon Sep 17 00:00:00 2001 From: Victor Vazquez Date: Mon, 3 Feb 2025 22:41:33 +0000 Subject: [PATCH 4/5] test cases --- .../provisioning/bicep/bicep_provider_test.go | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go index 63d4f747142..611572bf979 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go +++ b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go @@ -1355,3 +1355,54 @@ func TestInputsParameter(t *testing.T) { require.Equal(t, expectedInputsUpdated, inputsUpdated) } +func TestDefaultLocationToSelectFn(t *testing.T) { + t.Run("NoAllowedValuesOrMetadata", func(t *testing.T) { + param := azure.ArmTemplateParameterDefinition{} + result := defaultLocationToSelectFn(param) + require.Nil(t, result) + }) + + t.Run("AllowedValuesOnly", func(t *testing.T) { + param := azure.ArmTemplateParameterDefinition{ + AllowedValues: &[]any{"eastus", "westus"}, + } + result := defaultLocationToSelectFn(param) + require.NotNil(t, result) + require.Equal(t, "eastus", *result) + }) + + t.Run("MetadataOnly", func(t *testing.T) { + defaultLocation := "centralus" + param := azure.ArmTemplateParameterDefinition{ + Metadata: map[string]json.RawMessage{ + "azd": json.RawMessage(`{"type": "location", "default": "centralus"}`), + }, + } + result := defaultLocationToSelectFn(param) + require.NotNil(t, result) + require.Equal(t, defaultLocation, *result) + }) + + t.Run("AllowedValuesAndMetadata", func(t *testing.T) { + defaultLocation := "centralus" + param := azure.ArmTemplateParameterDefinition{ + AllowedValues: &[]any{"eastus", "westus"}, + Metadata: map[string]json.RawMessage{ + "azd": json.RawMessage(`{"type": "location", "default": "centralus"}`), + }, + } + result := defaultLocationToSelectFn(param) + require.NotNil(t, result) + require.Equal(t, defaultLocation, *result) + }) + + t.Run("InvalidMetadata", func(t *testing.T) { + param := azure.ArmTemplateParameterDefinition{ + Metadata: map[string]json.RawMessage{ + "azd": json.RawMessage(`{"type": "location"}`), + }, + } + result := defaultLocationToSelectFn(param) + require.Nil(t, result) + }) +} From 61395d69537a83bbfdd3592aedf2ebe7fac56019 Mon Sep 17 00:00:00 2001 From: Victor Vazquez Date: Tue, 4 Feb 2025 20:00:20 +0000 Subject: [PATCH 5/5] update function name and docs --- .../pkg/infra/provisioning/bicep/bicep_provider.go | 14 +++++++------- .../provisioning/bicep/bicep_provider_test.go | 10 +++++----- cli/azd/pkg/infra/provisioning/bicep/prompt.go | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go index ea393b1ab9b..78930b8232f 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go +++ b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go @@ -140,7 +140,7 @@ func (p *BicepProvider) EnsureEnv(ctx context.Context) error { } var defaultLocationToSelect *string if locationParamDefined { - defaultLocationToSelect = defaultLocationToSelectFn(locationParam) + defaultLocationToSelect = defaultPromptValue(locationParam) } err := provisioning.EnsureSubscriptionAndLocation( @@ -190,12 +190,12 @@ func locationParameterFilterImpl(param azure.ArmTemplateParameterDefinition, loc }) != -1 } -// defaultLocationToSelectFn resolves if there is an intention from a location parameter to use a default location. -// If the parameter has the @allowedValues set, it will return the first value from the array as the default. -// If the parameter has the location azd metadata, it will check if there is configuration to set a default location. -// If both @allowedValues and azd location metadata config are set, the metadata config will take precedence. -// If nothing is set, it will return nil. -func defaultLocationToSelectFn(locationParam azure.ArmTemplateParameterDefinition) *string { +// defaultPromptValue resolves if there is an intention from a location parameter to use a default location. +// +// If the parameter has AzdMetadataTypeLocation, with a default location set, the default location is returned. +// If the parameter has AllowedValues, the first option value is returned. +// Otherwise, nil is returned to indicate no user-provided default value. +func defaultPromptValue(locationParam azure.ArmTemplateParameterDefinition) *string { azdMetadata, has := locationParam.AzdMetadata() if has && azdMetadata.Type != nil && *azdMetadata.Type == azure.AzdMetadataTypeLocation && diff --git a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go index 611572bf979..27229912063 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go +++ b/cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go @@ -1358,7 +1358,7 @@ func TestInputsParameter(t *testing.T) { func TestDefaultLocationToSelectFn(t *testing.T) { t.Run("NoAllowedValuesOrMetadata", func(t *testing.T) { param := azure.ArmTemplateParameterDefinition{} - result := defaultLocationToSelectFn(param) + result := defaultPromptValue(param) require.Nil(t, result) }) @@ -1366,7 +1366,7 @@ func TestDefaultLocationToSelectFn(t *testing.T) { param := azure.ArmTemplateParameterDefinition{ AllowedValues: &[]any{"eastus", "westus"}, } - result := defaultLocationToSelectFn(param) + result := defaultPromptValue(param) require.NotNil(t, result) require.Equal(t, "eastus", *result) }) @@ -1378,7 +1378,7 @@ func TestDefaultLocationToSelectFn(t *testing.T) { "azd": json.RawMessage(`{"type": "location", "default": "centralus"}`), }, } - result := defaultLocationToSelectFn(param) + result := defaultPromptValue(param) require.NotNil(t, result) require.Equal(t, defaultLocation, *result) }) @@ -1391,7 +1391,7 @@ func TestDefaultLocationToSelectFn(t *testing.T) { "azd": json.RawMessage(`{"type": "location", "default": "centralus"}`), }, } - result := defaultLocationToSelectFn(param) + result := defaultPromptValue(param) require.NotNil(t, result) require.Equal(t, defaultLocation, *result) }) @@ -1402,7 +1402,7 @@ func TestDefaultLocationToSelectFn(t *testing.T) { "azd": json.RawMessage(`{"type": "location"}`), }, } - result := defaultLocationToSelectFn(param) + result := defaultPromptValue(param) require.Nil(t, result) }) } diff --git a/cli/azd/pkg/infra/provisioning/bicep/prompt.go b/cli/azd/pkg/infra/provisioning/bicep/prompt.go index 9f60f530ad4..2d067677b17 100644 --- a/cli/azd/pkg/infra/provisioning/bicep/prompt.go +++ b/cli/azd/pkg/infra/provisioning/bicep/prompt.go @@ -97,7 +97,7 @@ func (p *BicepProvider) promptForParameter( location, err := p.prompters.PromptLocation(ctx, p.env.GetSubscriptionId(), msg, func(loc account.Location) bool { return locationParameterFilterImpl(param, loc) - }, defaultLocationToSelectFn(param)) + }, defaultPromptValue(param)) if err != nil { return nil, err }