Skip to content

Commit

Permalink
Update HCL and go-cty to fix optional and default attributes (#32178)
Browse files Browse the repository at this point in the history
* Add test cases to verify all the default and optional issues are fixed

* actually commit all the tests

* update go-cty

* Update hcl
  • Loading branch information
liamcervante authored and crw committed Nov 18, 2022
1 parent 72a7f94 commit 70b7dcb
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 6 deletions.
4 changes: 2 additions & 2 deletions go.mod
Expand Up @@ -43,7 +43,7 @@ require (
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f
github.com/hashicorp/hcl/v2 v2.14.1
github.com/hashicorp/hcl/v2 v2.15.0
github.com/hashicorp/terraform-config-inspect v0.0.0-20210209133302-4fd17a0faac2
github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734
Expand Down Expand Up @@ -75,7 +75,7 @@ require (
github.com/tombuildsstuff/giovanni v0.15.1
github.com/xanzy/ssh-agent v0.3.1
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
github.com/zclconf/go-cty v1.12.0
github.com/zclconf/go-cty v1.12.1
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b
github.com/zclconf/go-cty-yaml v1.0.2
golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Expand Up @@ -387,8 +387,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f h1:UdxlrJz4JOnY8W+DbLISwf2B8WXEolNRA8BGCwI9jws=
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90=
github.com/hashicorp/hcl/v2 v2.14.1 h1:x0BpjfZ+CYdbiz+8yZTQ+gdLO7IXvOut7Da+XJayx34=
github.com/hashicorp/hcl/v2 v2.14.1/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
github.com/hashicorp/hcl/v2 v2.15.0 h1:CPDXO6+uORPjKflkWCCwoWc9uRp+zSIPcCQ+BrxV7m8=
github.com/hashicorp/hcl/v2 v2.15.0/go.mod h1:JRmR89jycNkrrqnMmvPDMd56n1rQJ2Q6KocSLCMCXng=
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d h1:9ARUJJ1VVynB176G1HCwleORqCaXm/Vx0uUi0dL26I0=
github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d/go.mod h1:Yog5+CPEM3c99L1CL2CFCYoSzgWm5vTU58idbRUaLik=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
Expand Down Expand Up @@ -619,8 +619,8 @@ github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/zclconf/go-cty v1.0.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.12.0 h1:F5E/vbilcrCtat9sYcEjlwwg1mDqbRTjyXR57nnx5sc=
github.com/zclconf/go-cty v1.12.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY=
github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
github.com/zclconf/go-cty-yaml v1.0.2 h1:dNyg4QLTrv2IfJpm7Wtxi55ed5gLGOlPrZ6kMd51hY0=
Expand Down
218 changes: 218 additions & 0 deletions internal/terraform/eval_variable_test.go
Expand Up @@ -92,6 +92,94 @@ func TestPrepareFinalInputVariableValue(t *testing.T) {
})
})
}
// https://github.com/hashicorp/terraform/issues/32152
// This variable was originally added to test that optional attribute
// metadata is stripped from empty default collections. Essentially, you
// should be able to mix and match custom and default values for the
// optional_list attribute.
variable "complex_type_with_empty_default_and_nested_optional" {
type = list(object({
name = string
optional_list = optional(list(object({
string = string
optional_string = optional(string)
})), [])
}))
}
// https://github.com/hashicorp/terraform/issues/32160#issuecomment-1302783910
// These variables were added to test the specific use case from this
// GitHub comment.
variable "empty_object_with_optional_nested_object_with_optional_bool" {
type = object({
thing = optional(object({
flag = optional(bool, false)
}))
})
default = {}
}
variable "populated_object_with_optional_nested_object_with_optional_bool" {
type = object({
thing = optional(object({
flag = optional(bool, false)
}))
})
default = {
thing = {}
}
}
variable "empty_object_with_default_nested_object_with_optional_bool" {
type = object({
thing = optional(object({
flag = optional(bool, false)
}), {})
})
default = {}
}
// https://github.com/hashicorp/terraform/issues/32160
// This variable was originally added to test that optional objects do
// get created containing only their defaults. Instead they should be
// left empty. We do not expect nested_object to be created just because
// optional_string has a default value.
variable "object_with_nested_object_with_required_and_optional_attributes" {
type = object({
nested_object = optional(object({
string = string
optional_string = optional(string, "optional")
}))
})
}
// https://github.com/hashicorp/terraform/issues/32157
// Similar to above, we want to see that merging combinations of the
// nested_object into a single collection doesn't crash because of
// inconsistent elements.
variable "list_with_nested_object_with_required_and_optional_attributes" {
type = list(object({
nested_object = optional(object({
string = string
optional_string = optional(string, "optional")
}))
}))
}
// https://github.com/hashicorp/terraform/issues/32109
// This variable was originally introduced to test the behaviour of
// the dynamic type constraint. You should be able to use the 'any'
// constraint and introduce empty, null, and populated values into the
// list.
variable "list_with_nested_list_of_any" {
type = list(object({
a = string
b = optional(list(any))
}))
default = [
{
a = "a"
},
{
a = "b"
b = [1]
}
]
}
`
cfg := testModuleInline(t, map[string]string{
"main.tf": cfgSrc,
Expand Down Expand Up @@ -496,6 +584,136 @@ func TestPrepareFinalInputVariableValue(t *testing.T) {
}),
``,
},
{
"complex_type_with_empty_default_and_nested_optional",
cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("abc"),
"optional_list": cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"string": cty.StringVal("child"),
"optional_string": cty.NullVal(cty.String),
}),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("def"),
"optional_list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
"string": cty.String,
"optional_string": cty.String,
}))),
}),
}),
cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("abc"),
"optional_list": cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"string": cty.StringVal("child"),
"optional_string": cty.NullVal(cty.String),
}),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("def"),
"optional_list": cty.ListValEmpty(cty.Object(map[string]cty.Type{
"string": cty.String,
"optional_string": cty.String,
})),
}),
}),
``,
},
{
"object_with_nested_object_with_required_and_optional_attributes",
cty.EmptyObjectVal,
cty.ObjectVal(map[string]cty.Value{
"nested_object": cty.NullVal(cty.Object(map[string]cty.Type{
"string": cty.String,
"optional_string": cty.String,
})),
}),
``,
},
{
"empty_object_with_optional_nested_object_with_optional_bool",
cty.NilVal,
cty.ObjectVal(map[string]cty.Value{
"thing": cty.NullVal(cty.Object(map[string]cty.Type{
"flag": cty.Bool,
})),
}),
``,
},
{
"populated_object_with_optional_nested_object_with_optional_bool",
cty.NilVal,
cty.ObjectVal(map[string]cty.Value{
"thing": cty.ObjectVal(map[string]cty.Value{
"flag": cty.False,
}),
}),
``,
},
{
"empty_object_with_default_nested_object_with_optional_bool",
cty.NilVal,
cty.ObjectVal(map[string]cty.Value{
"thing": cty.ObjectVal(map[string]cty.Value{
"flag": cty.False,
}),
}),
``,
},
{
"list_with_nested_object_with_required_and_optional_attributes",
cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"nested_object": cty.ObjectVal(map[string]cty.Value{
"string": cty.StringVal("string"),
"optional_string": cty.NullVal(cty.String),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"nested_object": cty.NullVal(cty.Object(map[string]cty.Type{
"string": cty.String,
"optional_string": cty.String,
})),
}),
}),
cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"nested_object": cty.ObjectVal(map[string]cty.Value{
"string": cty.StringVal("string"),
"optional_string": cty.StringVal("optional"),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"nested_object": cty.NullVal(cty.Object(map[string]cty.Type{
"string": cty.String,
"optional_string": cty.String,
})),
}),
}),
``,
},
{
"list_with_nested_list_of_any",
cty.NilVal,
cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("a"),
"b": cty.NullVal(cty.List(cty.Number)),
}),
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("b"),
"b": cty.ListVal([]cty.Value{
cty.NumberIntVal(1),
}),
}),
}),
``,
},

// sensitive
{
Expand Down

0 comments on commit 70b7dcb

Please sign in to comment.