@@ -124,7 +124,7 @@ func parameterDataSource() *schema.Resource {
124
124
}
125
125
var value string
126
126
if parameter .Default != "" {
127
- err := valueIsType (parameter .Type , parameter .Default )
127
+ err := valueIsType (parameter .Type , parameter .Default , cty. Path {cty. GetAttrStep { Name : "default" }} )
128
128
if err != nil {
129
129
return err
130
130
}
@@ -144,6 +144,8 @@ func parameterDataSource() *schema.Resource {
144
144
return diag .Errorf ("ephemeral parameter requires the default property" )
145
145
}
146
146
147
+ // TODO: Should we move this into the Valid() function on
148
+ // Parameter?
147
149
if len (parameter .Validation ) == 1 {
148
150
validation := & parameter .Validation [0 ]
149
151
err = validation .Valid (parameter .Type , value )
@@ -155,7 +157,12 @@ func parameterDataSource() *schema.Resource {
155
157
// Validate options
156
158
_ , parameter .FormType , err = ValidateFormType (parameter .Type , len (parameter .Option ), parameter .FormType )
157
159
if err != nil {
158
- return diag .FromErr (err )
160
+ return singleDiag (diag.Diagnostic {
161
+ Severity : diag .Error ,
162
+ Summary : "Invalid form_type for parameter" ,
163
+ Detail : err .Error (),
164
+ AttributePath : cty.Path {cty.GetAttrStep {Name : "form_type" }},
165
+ })
159
166
}
160
167
// Set the form_type back in case the value was changed.
161
168
// Eg via a default. If a user does not specify, a default value
@@ -380,7 +387,7 @@ func fixValidationResourceData(rawConfig cty.Value, validation interface{}) (int
380
387
return vArr , nil
381
388
}
382
389
383
- func valueIsType (typ OptionType , value string ) diag.Diagnostics {
390
+ func valueIsType (typ OptionType , value string , attrPath cty. Path ) diag.Diagnostics {
384
391
switch typ {
385
392
case OptionTypeNumber :
386
393
_ , err := strconv .ParseFloat (value , 64 )
@@ -393,10 +400,9 @@ func valueIsType(typ OptionType, value string) diag.Diagnostics {
393
400
return diag .Errorf ("%q is not a bool" , value )
394
401
}
395
402
case OptionTypeListString :
396
- var items []string
397
- err := json .Unmarshal ([]byte (value ), & items )
398
- if err != nil {
399
- return diag .Errorf ("%q is not an array of strings" , value )
403
+ _ , diags := valueIsListString (value , attrPath )
404
+ if diags .HasError () {
405
+ return diags
400
406
}
401
407
case OptionTypeString :
402
408
// Anything is a string!
@@ -409,13 +415,14 @@ func valueIsType(typ OptionType, value string) diag.Diagnostics {
409
415
func (v * Parameter ) Valid () diag.Diagnostics {
410
416
// optionType might differ from parameter.Type. This is ok, and parameter.Type
411
417
// should be used for the value type, and optionType for options.
412
- optionType , formType , err := ValidateFormType (v .Type , len (v .Option ), v .FormType )
418
+ optionType , _ , err := ValidateFormType (v .Type , len (v .Option ), v .FormType )
413
419
if err != nil {
414
- return diag .FromErr (err )
415
- }
416
-
417
- if formType != v .FormType {
418
- return diag .FromErr (fmt .Errorf ("form_type %q is not valid for type %q" , v .FormType , v .Type ))
420
+ return singleDiag (diag.Diagnostic {
421
+ Severity : diag .Error ,
422
+ Summary : "Invalid form_type for parameter" ,
423
+ Detail : err .Error (),
424
+ AttributePath : cty.Path {cty.GetAttrStep {Name : "form_type" }},
425
+ })
419
426
}
420
427
421
428
optionNames := map [string ]interface {}{}
@@ -424,13 +431,21 @@ func (v *Parameter) Valid() diag.Diagnostics {
424
431
for _ , option := range v .Option {
425
432
_ , exists := optionNames [option .Name ]
426
433
if exists {
427
- return diag .FromErr (fmt .Errorf ("multiple options cannot have the same name %q" , option .Name ))
434
+ return singleDiag (diag.Diagnostic {
435
+ Severity : diag .Error ,
436
+ Summary : "Option names must be unique." ,
437
+ Detail : fmt .Sprintf ("multiple options found with the same name %q" , option .Name ),
438
+ })
428
439
}
429
440
_ , exists = optionValues [option .Value ]
430
441
if exists {
431
- return diag .FromErr (fmt .Errorf ("multiple options cannot have the same value %q" , option .Value ))
442
+ return singleDiag (diag.Diagnostic {
443
+ Severity : diag .Error ,
444
+ Summary : "Option values must be unique." ,
445
+ Detail : fmt .Sprintf ("multiple options found with the same value %q" , option .Value ),
446
+ })
432
447
}
433
- diags := valueIsType (optionType , option .Value )
448
+ diags := valueIsType (optionType , option .Value , cty. Path {} )
434
449
if diags .HasError () {
435
450
return diags
436
451
}
@@ -439,15 +454,13 @@ func (v *Parameter) Valid() diag.Diagnostics {
439
454
}
440
455
}
441
456
442
- if v .Default != "" {
457
+ if v .Default != "" && len ( v . Option ) > 0 {
443
458
if v .Type == OptionTypeListString && optionType == OptionTypeString {
444
459
// If the type is list(string) and optionType is string, we have
445
460
// to ensure all elements of the default exist as options.
446
- var defaultValues []string
447
- // TODO: We do this unmarshal in a few spots. It should be standardized.
448
- err = json .Unmarshal ([]byte (v .Default ), & defaultValues )
449
- if err != nil {
450
- return diag .FromErr (fmt .Errorf ("default value %q is not a list of strings" , v .Default ))
461
+ defaultValues , diags := valueIsListString (v .Default , cty.Path {cty.GetAttrStep {Name : "default" }})
462
+ if diags .HasError () {
463
+ return diags
451
464
}
452
465
453
466
// missing is used to construct a more helpful error message
@@ -460,15 +473,25 @@ func (v *Parameter) Valid() diag.Diagnostics {
460
473
}
461
474
462
475
if len (missing ) > 0 {
463
- return diag .FromErr (fmt .Errorf (
464
- "default value %q is not a valid option, values %q are missing from the option" ,
465
- v .Default , strings .Join (missing , ", " ),
466
- ))
476
+ return singleDiag (diag.Diagnostic {
477
+ Severity : diag .Error ,
478
+ Summary : "Default values must be a valid option" ,
479
+ Detail : fmt .Sprintf (
480
+ "default value %q is not a valid option, values %q are missing from the options" ,
481
+ v .Default , strings .Join (missing , ", " ),
482
+ ),
483
+ AttributePath : cty.Path {cty.GetAttrStep {Name : "default" }},
484
+ })
467
485
}
468
486
} else {
469
487
_ , defaultIsValid := optionValues [v .Default ]
470
488
if ! defaultIsValid {
471
- return diag .FromErr (fmt .Errorf ("%q default value %q must be defined as one of options" , v .FormType , v .Default ))
489
+ return singleDiag (diag.Diagnostic {
490
+ Severity : diag .Error ,
491
+ Summary : "Default value must be a valid option" ,
492
+ Detail : fmt .Sprintf ("the value %q must be defined as one of options" , v .Default ),
493
+ AttributePath : cty.Path {cty.GetAttrStep {Name : "default" }},
494
+ })
472
495
}
473
496
}
474
497
}
@@ -536,6 +559,20 @@ func (v *Validation) Valid(typ OptionType, value string) error {
536
559
return nil
537
560
}
538
561
562
+ func valueIsListString (value string , path cty.Path ) ([]string , diag.Diagnostics ) {
563
+ var items []string
564
+ err := json .Unmarshal ([]byte (value ), & items )
565
+ if err != nil {
566
+ return nil , singleDiag (diag.Diagnostic {
567
+ Severity : diag .Error ,
568
+ Summary : fmt .Sprintf ("When using list(string) type, value must be a json encoded list of strings" ),
569
+ Detail : fmt .Sprintf ("value %q is not a valid list of strings" , value ),
570
+ AttributePath : path ,
571
+ })
572
+ }
573
+ return items , nil
574
+ }
575
+
539
576
// ParameterEnvironmentVariable returns the environment variable to specify for
540
577
// a parameter by it's name. It's hashed because spaces and special characters
541
578
// can be used in parameter names that may not be valid in env vars.
@@ -563,3 +600,7 @@ func (v *Validation) errorRendered(value string) error {
563
600
"{value}" , value )
564
601
return xerrors .Errorf (r .Replace (v .Error ))
565
602
}
603
+
604
+ func singleDiag (diagnostic diag.Diagnostic ) diag.Diagnostics {
605
+ return diag.Diagnostics {diagnostic }
606
+ }
0 commit comments