Merge pull request #22530 from hashicorp/jbardin/validations
MinItems and MaxItems validations
This commit is contained in:
commit
9f5fa2acf6
|
@ -8,9 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// CoerceValue attempts to force the given value to conform to the type
|
// CoerceValue attempts to force the given value to conform to the type
|
||||||
// implied by the receiever, while also applying the same validation and
|
// implied by the receiever.
|
||||||
// transformation rules that would be applied by the decoder specification
|
|
||||||
// returned by method DecoderSpec.
|
|
||||||
//
|
//
|
||||||
// This is useful in situations where a configuration must be derived from
|
// This is useful in situations where a configuration must be derived from
|
||||||
// an already-decoded value. It is always better to decode directly from
|
// an already-decoded value. It is always better to decode directly from
|
||||||
|
@ -83,16 +81,8 @@ func (b *Block) coerceValue(in cty.Value, path cty.Path) (cty.Value, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cty.UnknownVal(b.ImpliedType()), err
|
return cty.UnknownVal(b.ImpliedType()), err
|
||||||
}
|
}
|
||||||
case blockS.MinItems != 1 && blockS.MaxItems != 1:
|
|
||||||
if blockS.Nesting == NestingGroup {
|
|
||||||
attrs[typeName] = blockS.EmptyValue()
|
|
||||||
} else {
|
|
||||||
attrs[typeName] = cty.NullVal(blockS.ImpliedType())
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
// We use the word "attribute" here because we're talking about
|
attrs[typeName] = blockS.EmptyValue()
|
||||||
// the cty sense of that word rather than the HCL sense.
|
|
||||||
return cty.UnknownVal(b.ImpliedType()), path.NewErrorf("attribute %q is required", typeName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case NestingList:
|
case NestingList:
|
||||||
|
|
|
@ -288,8 +288,10 @@ func TestCoerceValue(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cty.EmptyObjectVal,
|
cty.EmptyObjectVal,
|
||||||
cty.DynamicVal,
|
cty.ObjectVal(map[string]cty.Value{
|
||||||
`attribute "foo" is required`,
|
"foo": cty.NullVal(cty.EmptyObject),
|
||||||
|
}),
|
||||||
|
``,
|
||||||
},
|
},
|
||||||
"unknown nested list": {
|
"unknown nested list": {
|
||||||
&Block{
|
&Block{
|
||||||
|
|
|
@ -35,7 +35,8 @@ func (b *Block) DecoderSpec() hcldec.Spec {
|
||||||
|
|
||||||
// We can only validate 0 or 1 for MinItems, because a dynamic block
|
// We can only validate 0 or 1 for MinItems, because a dynamic block
|
||||||
// may satisfy any number of min items while only having a single
|
// may satisfy any number of min items while only having a single
|
||||||
// block in the config.
|
// block in the config. We cannot validate MaxItems because a
|
||||||
|
// configuration may have any number of dynamic blocks
|
||||||
minItems := 0
|
minItems := 0
|
||||||
if blockS.MinItems > 1 {
|
if blockS.MinItems > 1 {
|
||||||
minItems = 1
|
minItems = 1
|
||||||
|
@ -46,7 +47,7 @@ func (b *Block) DecoderSpec() hcldec.Spec {
|
||||||
ret[name] = &hcldec.BlockSpec{
|
ret[name] = &hcldec.BlockSpec{
|
||||||
TypeName: name,
|
TypeName: name,
|
||||||
Nested: childSpec,
|
Nested: childSpec,
|
||||||
Required: blockS.MinItems == 1 && blockS.MaxItems >= 1,
|
Required: blockS.MinItems == 1,
|
||||||
}
|
}
|
||||||
if blockS.Nesting == NestingGroup {
|
if blockS.Nesting == NestingGroup {
|
||||||
ret[name] = &hcldec.DefaultSpec{
|
ret[name] = &hcldec.DefaultSpec{
|
||||||
|
@ -66,14 +67,12 @@ func (b *Block) DecoderSpec() hcldec.Spec {
|
||||||
TypeName: name,
|
TypeName: name,
|
||||||
Nested: childSpec,
|
Nested: childSpec,
|
||||||
MinItems: minItems,
|
MinItems: minItems,
|
||||||
MaxItems: blockS.MaxItems,
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret[name] = &hcldec.BlockListSpec{
|
ret[name] = &hcldec.BlockListSpec{
|
||||||
TypeName: name,
|
TypeName: name,
|
||||||
Nested: childSpec,
|
Nested: childSpec,
|
||||||
MinItems: minItems,
|
MinItems: minItems,
|
||||||
MaxItems: blockS.MaxItems,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NestingSet:
|
case NestingSet:
|
||||||
|
@ -86,7 +85,6 @@ func (b *Block) DecoderSpec() hcldec.Spec {
|
||||||
TypeName: name,
|
TypeName: name,
|
||||||
Nested: childSpec,
|
Nested: childSpec,
|
||||||
MinItems: minItems,
|
MinItems: minItems,
|
||||||
MaxItems: blockS.MaxItems,
|
|
||||||
}
|
}
|
||||||
case NestingMap:
|
case NestingMap:
|
||||||
// We prefer to use a list where possible, since it makes our
|
// We prefer to use a list where possible, since it makes our
|
||||||
|
|
|
@ -354,7 +354,7 @@ func TestBlockDecoderSpec(t *testing.T) {
|
||||||
cty.EmptyObjectVal,
|
cty.EmptyObjectVal,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
1, // too many "foo" blocks
|
0, // max items cannot be validated during decode
|
||||||
},
|
},
|
||||||
// dynamic blocks may fulfill MinItems, but there is only one block to
|
// dynamic blocks may fulfill MinItems, but there is only one block to
|
||||||
// decode.
|
// decode.
|
||||||
|
|
Loading…
Reference in New Issue