Skip to content

Commit f218aab

Browse files
committed
Use mapstructure for parsing parameters
1 parent 6ab940e commit f218aab

File tree

2 files changed

+89
-99
lines changed

2 files changed

+89
-99
lines changed

provider/parameter.go

Lines changed: 81 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -12,120 +12,105 @@ import (
1212
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1313
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1414
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
15+
"github.com/mitchellh/mapstructure"
1516
)
1617

18+
type Option struct {
19+
Name string
20+
Description string
21+
Value string
22+
Icon string
23+
}
24+
25+
type Validation struct {
26+
Min int
27+
Max int
28+
Regex string
29+
}
30+
31+
type Parameter struct {
32+
Value string
33+
Name string
34+
Description string
35+
Type string
36+
Immutable bool
37+
Default string
38+
Icon string
39+
Option []Option
40+
Validation []Validation
41+
}
42+
1743
func parameterDataSource() *schema.Resource {
1844
return &schema.Resource{
1945
Description: "Use this data source to configure editable options for workspaces.",
2046
ReadContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
2147
rd.SetId(uuid.NewString())
2248

23-
name := rd.Get("name").(string)
24-
typ := rd.Get("type").(string)
49+
var parameter Parameter
50+
err := mapstructure.Decode(struct {
51+
Value interface{}
52+
Name interface{}
53+
Description interface{}
54+
Type interface{}
55+
Immutable interface{}
56+
Default interface{}
57+
Icon interface{}
58+
Option interface{}
59+
Validation interface{}
60+
}{
61+
Value: rd.Get("value"),
62+
Name: rd.Get("name"),
63+
Description: rd.Get("description"),
64+
Type: rd.Get("type"),
65+
Immutable: rd.Get("immutable"),
66+
Default: rd.Get("default"),
67+
Icon: rd.Get("icon"),
68+
Option: rd.Get("option"),
69+
Validation: rd.Get("validation"),
70+
}, &parameter)
71+
if err != nil {
72+
return diag.Errorf("decode parameter: %s", err)
73+
}
2574
var value string
26-
rawDefaultValue, ok := rd.GetOk("default")
27-
if ok {
28-
defaultValue := rawDefaultValue.(string)
29-
err := valueIsType(typ, defaultValue)
75+
if parameter.Default != "" {
76+
err := valueIsType(parameter.Type, parameter.Default)
3077
if err != nil {
3178
return err
3279
}
33-
value = defaultValue
80+
value = parameter.Default
3481
}
35-
envValue, ok := os.LookupEnv(fmt.Sprintf("CODER_PARAMETER_%s", name))
82+
envValue, ok := os.LookupEnv(fmt.Sprintf("CODER_PARAMETER_%s", parameter.Name))
3683
if ok {
3784
value = envValue
3885
}
3986
rd.Set("value", value)
4087

41-
rawValidation, exists := rd.GetOk("validation")
42-
var (
43-
validationRegex string
44-
validationMin int
45-
validationMax int
46-
)
47-
if exists {
48-
validationArray, valid := rawValidation.([]interface{})
49-
if !valid {
50-
return diag.Errorf("validation is of wrong type %T", rawValidation)
51-
}
52-
validation, valid := validationArray[0].(map[string]interface{})
53-
if !valid {
54-
return diag.Errorf("validation is of wrong type %T", validation)
55-
}
56-
rawRegex, ok := validation["regex"]
57-
if ok {
58-
validationRegex, ok = rawRegex.(string)
59-
if !ok {
60-
return diag.Errorf("validation regex is of wrong type %T", rawRegex)
61-
}
62-
}
63-
rawMin, ok := validation["min"]
64-
if ok {
65-
validationMin, ok = rawMin.(int)
66-
if !ok {
67-
return diag.Errorf("validation min is wrong type %T", rawMin)
68-
}
69-
}
70-
rawMax, ok := validation["max"]
71-
if ok {
72-
validationMax, ok = rawMax.(int)
73-
if !ok {
74-
return diag.Errorf("validation max is wrong type %T", rawMax)
75-
}
88+
if len(parameter.Validation) == 1 {
89+
validation := &parameter.Validation[0]
90+
err = validation.Valid(parameter.Type, value)
91+
if err != nil {
92+
return diag.FromErr(err)
7693
}
7794
}
7895

79-
err := ValueValidatesType(typ, value, validationRegex, validationMin, validationMax)
80-
if err != nil {
81-
return diag.FromErr(err)
82-
}
83-
84-
rawOptions, exists := rd.GetOk("option")
85-
if exists {
86-
rawArrayOptions, valid := rawOptions.([]interface{})
87-
if !valid {
88-
return diag.Errorf("options is of wrong type %T", rawArrayOptions)
89-
}
90-
optionDisplayNames := map[string]interface{}{}
91-
optionValues := map[string]interface{}{}
92-
for _, rawOption := range rawArrayOptions {
93-
option, valid := rawOption.(map[string]interface{})
94-
if !valid {
95-
return diag.Errorf("option is of wrong type %T", rawOption)
96-
}
97-
rawName, ok := option["name"]
98-
if !ok {
99-
return diag.Errorf("no name for %+v", option)
100-
}
101-
displayName, ok := rawName.(string)
102-
if !ok {
103-
return diag.Errorf("display name is of wrong type %T", displayName)
104-
}
105-
_, exists := optionDisplayNames[displayName]
96+
if len(parameter.Option) > 0 {
97+
names := map[string]interface{}{}
98+
values := map[string]interface{}{}
99+
for _, option := range parameter.Option {
100+
_, exists := names[option.Name]
106101
if exists {
107-
return diag.Errorf("multiple options cannot have the same display name %q", displayName)
102+
return diag.Errorf("multiple options cannot have the same name %q", option.Name)
108103
}
109-
110-
rawValue, ok := option["value"]
111-
if !ok {
112-
return diag.Errorf("no value for %+v\n", option)
113-
}
114-
value, ok := rawValue.(string)
115-
if !ok {
116-
return diag.Errorf("")
117-
}
118-
_, exists = optionValues[value]
104+
_, exists = values[option.Value]
119105
if exists {
120-
return diag.Errorf("multiple options cannot have the same value %q", value)
106+
return diag.Errorf("multiple options cannot have the same value %q", option.Value)
121107
}
122-
err := valueIsType(typ, value)
108+
err := valueIsType(parameter.Type, option.Value)
123109
if err != nil {
124110
return err
125111
}
126-
127-
optionValues[value] = nil
128-
optionDisplayNames[displayName] = nil
112+
values[option.Value] = nil
113+
names[option.Name] = nil
129114
}
130115
}
131116

@@ -280,26 +265,26 @@ func valueIsType(typ, value string) diag.Diagnostics {
280265
return nil
281266
}
282267

283-
func ValueValidatesType(typ, value, regex string, min, max int) error {
268+
func (v *Validation) Valid(typ, value string) error {
284269
if typ != "number" {
285-
if min != 0 {
270+
if v.Min != 0 {
286271
return fmt.Errorf("a min cannot be specified for a %s type", typ)
287272
}
288-
if max != 0 {
273+
if v.Max != 0 {
289274
return fmt.Errorf("a max cannot be specified for a %s type", typ)
290275
}
291276
}
292-
if typ != "string" && regex != "" {
277+
if typ != "string" && v.Regex != "" {
293278
return fmt.Errorf("a regex cannot be specified for a %s type", typ)
294279
}
295280
switch typ {
296281
case "bool":
297282
return nil
298283
case "string":
299-
if regex == "" {
284+
if v.Regex == "" {
300285
return nil
301286
}
302-
regex, err := regexp.Compile(regex)
287+
regex, err := regexp.Compile(v.Regex)
303288
if err != nil {
304289
return fmt.Errorf("compile regex %q: %s", regex, err)
305290
}
@@ -312,11 +297,11 @@ func ValueValidatesType(typ, value, regex string, min, max int) error {
312297
if err != nil {
313298
return fmt.Errorf("parse value %s as int: %s", value, err)
314299
}
315-
if num < min {
316-
return fmt.Errorf("provided value %d is less than the minimum %d", num, min)
300+
if num < v.Min {
301+
return fmt.Errorf("provided value %d is less than the minimum %d", num, v.Min)
317302
}
318-
if num > max {
319-
return fmt.Errorf("provided value %d is more than the maximum %d", num, max)
303+
if num > v.Max {
304+
return fmt.Errorf("provided value %d is more than the maximum %d", num, v.Max)
320305
}
321306
}
322307
return nil

provider/parameter_test.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ data "coder_parameter" "region" {
188188
}
189189
`,
190190
}, {
191-
Name: "DuplicateOptionDisplayName",
191+
Name: "DuplicateOptionName",
192192
Config: `
193193
data "coder_parameter" "region" {
194194
name = "Region"
@@ -203,7 +203,7 @@ data "coder_parameter" "region" {
203203
}
204204
}
205205
`,
206-
ExpectError: regexp.MustCompile("cannot have the same display name"),
206+
ExpectError: regexp.MustCompile("cannot have the same name"),
207207
}, {
208208
Name: "DuplicateOptionValue",
209209
Config: `
@@ -300,7 +300,12 @@ func TestValueValidatesType(t *testing.T) {
300300
tc := tc
301301
t.Run(tc.Name, func(t *testing.T) {
302302
t.Parallel()
303-
err := provider.ValueValidatesType(tc.Type, tc.Value, tc.Regex, tc.Min, tc.Max)
303+
v := &provider.Validation{
304+
Min: tc.Min,
305+
Max: tc.Max,
306+
Regex: tc.Regex,
307+
}
308+
err := v.Valid(tc.Type, tc.Value)
304309
if tc.Error != nil {
305310
require.True(t, tc.Error.MatchString(err.Error()))
306311
}

0 commit comments

Comments
 (0)