Skip to content

Commit f4a3ebc

Browse files
committed
add parameter package
1 parent 0419d07 commit f4a3ebc

File tree

3 files changed

+269
-51
lines changed

3 files changed

+269
-51
lines changed

internal/provider/parameter.go

Lines changed: 118 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net/url"
77
"os"
8+
"regexp"
89
"strconv"
910

1011
"github.com/google/uuid"
@@ -37,6 +38,49 @@ func parameterDataSource() *schema.Resource {
3738
}
3839
rd.Set("value", value)
3940

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+
}
76+
}
77+
}
78+
79+
err := ValueValidatesType(typ, value, validationRegex, validationMin, validationMax)
80+
if err != nil {
81+
return diag.FromErr(err)
82+
}
83+
4084
rawOptions, exists := rd.GetOk("option")
4185
if exists {
4286
rawArrayOptions, valid := rawOptions.([]interface{})
@@ -91,28 +135,30 @@ func parameterDataSource() *schema.Resource {
91135
"value": {
92136
Type: schema.TypeString,
93137
Computed: true,
94-
Description: "The output value of a parameter.",
138+
Description: "The output value of the parameter.",
95139
},
96140
"name": {
97141
Type: schema.TypeString,
98142
Required: true,
99-
Description: "The name of the parameter as it appears in the interface. If this is changed, the parameter will need to be re-updated by developers.",
143+
Description: "The name of the parameter as it will appear in the interface. If this is changed, developers will be re-prompted for a new value.",
100144
},
101145
"description": {
102146
Type: schema.TypeString,
103147
Optional: true,
104-
Description: "Explain what the parameter does.",
148+
Description: "Describe what this parameter does.",
105149
},
106150
"type": {
107151
Type: schema.TypeString,
108152
Default: "string",
109153
Optional: true,
110154
ValidateFunc: validation.StringInSlice([]string{"number", "string", "bool"}, false),
155+
Description: `The type of this parameter. Must be one of: "number", "string", or "bool".`,
111156
},
112157
"immutable": {
113158
Type: schema.TypeBool,
114159
Optional: true,
115-
Description: "Whether the value can be changed after it's set initially.",
160+
Default: true,
161+
Description: "Whether this value can be changed after workspace creation. This can be destructive for values like region, so use with caution!",
116162
},
117163
"default": {
118164
Type: schema.TypeString,
@@ -136,11 +182,12 @@ func parameterDataSource() *schema.Resource {
136182
},
137183
},
138184
"option": {
139-
Type: schema.TypeList,
140-
Description: "Each \"option\" block defines a single displayable value for a user to select.",
141-
ForceNew: true,
142-
Optional: true,
143-
MaxItems: 64,
185+
Type: schema.TypeList,
186+
Description: "Each \"option\" block defines a value for a user to select from.",
187+
ForceNew: true,
188+
Optional: true,
189+
MaxItems: 64,
190+
ConflictsWith: []string{"validation"},
144191
Elem: &schema.Resource{
145192
Schema: map[string]*schema.Schema{
146193
"name": {
@@ -151,13 +198,13 @@ func parameterDataSource() *schema.Resource {
151198
},
152199
"description": {
153200
Type: schema.TypeString,
154-
Description: "Add a description to select this item.",
201+
Description: "Describe what selecting this value does.",
155202
ForceNew: true,
156203
Optional: true,
157204
},
158205
"value": {
159206
Type: schema.TypeString,
160-
Description: "The value of this option.",
207+
Description: "The value of this option set on the parameter if selected.",
161208
ForceNew: true,
162209
Required: true,
163210
},
@@ -180,26 +227,31 @@ func parameterDataSource() *schema.Resource {
180227
},
181228
},
182229
"validation": {
183-
Type: schema.TypeSet,
184-
MaxItems: 1,
185-
Optional: true,
230+
Type: schema.TypeList,
231+
MaxItems: 1,
232+
Optional: true,
233+
Description: "Validate the input of a parameter.",
234+
ConflictsWith: []string{"option"},
186235
Elem: &schema.Resource{
187236
Schema: map[string]*schema.Schema{
188237
"min": {
189-
Type: schema.TypeInt,
190-
Optional: true,
191-
Default: 0,
192-
Description: "The minimum for a number to be.",
238+
Type: schema.TypeInt,
239+
Optional: true,
240+
Default: 0,
241+
Description: "The minimum of a number parameter.",
242+
RequiredWith: []string{"validation.0.max"},
193243
},
194244
"max": {
195-
Type: schema.TypeInt,
196-
Optional: true,
197-
Description: "The maximum for a number to be.",
245+
Type: schema.TypeInt,
246+
Optional: true,
247+
Description: "The maximum of a number parameter.",
248+
RequiredWith: []string{"validation.0.min"},
198249
},
199250
"regex": {
200-
Type: schema.TypeString,
201-
ExactlyOneOf: []string{"min", "max"},
202-
Optional: true,
251+
Type: schema.TypeString,
252+
ConflictsWith: []string{"validation.0.min", "validation.0.max"},
253+
Description: "A regex for the input parameter to match against.",
254+
Optional: true,
203255
},
204256
},
205257
},
@@ -227,3 +279,45 @@ func valueIsType(typ, value string) diag.Diagnostics {
227279
}
228280
return nil
229281
}
282+
283+
func ValueValidatesType(typ, value, regex string, min, max int) error {
284+
if typ != "number" {
285+
if min != 0 {
286+
return fmt.Errorf("a min cannot be specified for a %s type", typ)
287+
}
288+
if max != 0 {
289+
return fmt.Errorf("a max cannot be specified for a %s type", typ)
290+
}
291+
}
292+
if typ != "string" && regex != "" {
293+
return fmt.Errorf("a regex cannot be specified for a %s type", typ)
294+
}
295+
switch typ {
296+
case "bool":
297+
return nil
298+
case "string":
299+
if regex == "" {
300+
return nil
301+
}
302+
regex, err := regexp.Compile(regex)
303+
if err != nil {
304+
return fmt.Errorf("compile regex %q: %s", regex, err)
305+
}
306+
matched := regex.MatchString(value)
307+
if !matched {
308+
return fmt.Errorf("value %q does not match %q", value, regex)
309+
}
310+
case "number":
311+
num, err := strconv.Atoi(value)
312+
if err != nil {
313+
return fmt.Errorf("parse value %s as int: %s", value, err)
314+
}
315+
if num < min {
316+
return fmt.Errorf("provided value %d is less than the minimum %d", num, min)
317+
}
318+
if num > max {
319+
return fmt.Errorf("provided value %d is more than the maximum %d", num, max)
320+
}
321+
}
322+
return nil
323+
}

0 commit comments

Comments
 (0)