Skip to content

Commit

Permalink
Allows prompting for for bicep parameters that reference empty or not…
Browse files Browse the repository at this point in the history
… set environment variables (#2896)

Fixes #2895 & #1910

When main.parameters.json references an empty or not set value expression azd will prompt the user for a value unless the parameter also defines a default value.
  • Loading branch information
wbreza committed Oct 23, 2023
1 parent 8926982 commit af84a93
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 5 deletions.
36 changes: 31 additions & 5 deletions cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go
Expand Up @@ -13,6 +13,7 @@ import (
"math"
"os"
"path/filepath"
"reflect"
"slices"
"strconv"
"strings"
Expand Down Expand Up @@ -1861,11 +1862,15 @@ func (p *BicepProvider) ensureParameters(
param := template.Parameters[key]

// If a value is explicitly configured via a parameters file, use it.
// unless the parameter value inference is nil/empty
if v, has := parameters[key]; has {
configuredParameters[key] = azure.ArmParameterValue{
Value: armParameterFileValue(p.mapBicepTypeToInterfaceType(param.Type), v.Value),
paramValue := armParameterFileValue(p.mapBicepTypeToInterfaceType(param.Type), v.Value, param.DefaultValue)
if paramValue != nil {
configuredParameters[key] = azure.ArmParameterValue{
Value: paramValue,
}
continue
}
continue
}

// If this parameter has a default, then there is no need for us to configure it.
Expand Down Expand Up @@ -1930,7 +1935,12 @@ func (p *BicepProvider) ensureParameters(
}

// Convert the ARM parameters file value into a value suitable for deployment
func armParameterFileValue(paramType ParameterType, value any) any {
func armParameterFileValue(paramType ParameterType, value any, defaultValue any) any {
// Quick return if the value being converted is not a string
if value == nil || reflect.TypeOf(value).Kind() != reflect.String {
return value
}

// Relax the handling of bool and number types to accept convertible strings
switch paramType {
case ParameterTypeBoolean:
Expand All @@ -1945,9 +1955,25 @@ func armParameterFileValue(paramType ParameterType, value any) any {
return intVal
}
}
case ParameterTypeString:
// Use Cases
// 1. Non-empty input value, return input value (no prompt)
// 2. Empty input value and no default - return nil (prompt user)
// 3. Empty input value and non-empty default - return empty input string (no prompt)
paramVal, paramValid := value.(string)
if paramValid && paramVal != "" {
return paramVal
}

defaultVal, hasDefault := defaultValue.(string)
if hasDefault && paramValid && paramVal != defaultVal {
return paramVal
}
default:
return value
}

return value
return nil
}

func isValueAssignableToParameterType(paramType ParameterType, value any) bool {
Expand Down
71 changes: 71 additions & 0 deletions cli/azd/pkg/infra/provisioning/bicep/bicep_provider_test.go
Expand Up @@ -1022,6 +1022,77 @@ func TestUserDefinedTypes(t *testing.T) {
}, customOutput.Metadata)
}

func Test_armParameterFileValue(t *testing.T) {
t.Run("NilValue", func(t *testing.T) {
actual := armParameterFileValue(ParameterTypeString, nil, nil)
require.Nil(t, actual)
})

t.Run("StringWithValue", func(t *testing.T) {
expected := "value"
actual := armParameterFileValue(ParameterTypeString, expected, nil)
require.Equal(t, expected, actual)
})

t.Run("EmptyString", func(t *testing.T) {
input := ""
actual := armParameterFileValue(ParameterTypeString, input, nil)
require.Nil(t, actual)
})

t.Run("EmptyStringWithNonEmptyDefault", func(t *testing.T) {
expected := ""
actual := armParameterFileValue(ParameterTypeString, expected, "not-empty")
require.Equal(t, expected, actual)
})

t.Run("EmptyStringWithEmptyDefault", func(t *testing.T) {
input := ""
actual := armParameterFileValue(ParameterTypeString, input, "")
require.Nil(t, actual)
})

t.Run("ValidBool", func(t *testing.T) {
expected := true
actual := armParameterFileValue(ParameterTypeBoolean, expected, nil)
require.Equal(t, expected, actual)
})

t.Run("ActualBool", func(t *testing.T) {
expected := true
actual := armParameterFileValue(ParameterTypeBoolean, "true", nil)
require.Equal(t, expected, actual)
})

t.Run("InvalidBool", func(t *testing.T) {
actual := armParameterFileValue(ParameterTypeBoolean, "NotABool", nil)
require.Nil(t, actual)
})

t.Run("ValidInt", func(t *testing.T) {
var expected int64 = 42
actual := armParameterFileValue(ParameterTypeNumber, "42", nil)
require.Equal(t, expected, actual)
})

t.Run("ActualInt", func(t *testing.T) {
var expected int64 = 42
actual := armParameterFileValue(ParameterTypeNumber, expected, nil)
require.Equal(t, expected, actual)
})

t.Run("InvalidInt", func(t *testing.T) {
actual := armParameterFileValue(ParameterTypeNumber, "NotAnInt", nil)
require.Nil(t, actual)
})

t.Run("Array", func(t *testing.T) {
expected := []string{"a", "b", "c"}
actual := armParameterFileValue(ParameterTypeArray, expected, nil)
require.Equal(t, expected, actual)
})
}

const userDefinedParamsSample = `{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"languageVersion": "2.0",
Expand Down

0 comments on commit af84a93

Please sign in to comment.