From ffcf9fc51b961d2f7730b4f64c635e98c9940527 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Fri, 5 Apr 2019 10:33:53 -0700 Subject: [PATCH] lang/blocktoattr: Apply fixup within already-fixed-up blocks too When a top-level list-of-object contains an attribute that is also list-of-object we need to do the fixup again inside the nested body (using our synthetic attributes-only schema) so that the attr-as-blocks mechanism can apply within the nested blocks too. --- lang/blocktoattr/fixup.go | 3 +- lang/blocktoattr/fixup_test.go | 52 +++++++++++++++++++++++++++++- lang/blocktoattr/variables_test.go | 33 +++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/lang/blocktoattr/fixup.go b/lang/blocktoattr/fixup.go index 29a0f0bad..d8c2e7752 100644 --- a/lang/blocktoattr/fixup.go +++ b/lang/blocktoattr/fixup.go @@ -152,7 +152,8 @@ func (e *fixupBlocksExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic vals := make([]cty.Value, len(e.blocks)) var diags hcl.Diagnostics for i, block := range e.blocks { - val, blockDiags := hcldec.Decode(block.Body, spec, ctx) + body := FixUpBlockAttrs(block.Body, schema) + val, blockDiags := hcldec.Decode(body, spec, ctx) diags = append(diags, blockDiags...) if val == cty.NilVal { val = cty.UnknownVal(e.ety) diff --git a/lang/blocktoattr/fixup_test.go b/lang/blocktoattr/fixup_test.go index 2a772989c..20f71069e 100644 --- a/lang/blocktoattr/fixup_test.go +++ b/lang/blocktoattr/fixup_test.go @@ -216,7 +216,7 @@ foo { }), }), }, - "nested fixup": { + "fixup inside block": { src: ` container { foo { @@ -262,6 +262,56 @@ container { }), }), }, + "fixup inside attribute-as-block": { + src: ` +container { + foo { + bar = "baz" + } + foo { + bar = "boop" + } +} +container { + foo { + bar = beep + } +} +`, + schema: &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "container": { + Type: cty.List(cty.Object(map[string]cty.Type{ + "foo": cty.List(cty.Object(map[string]cty.Type{ + "bar": cty.String, + })), + })), + Optional: true, + }, + }, + }, + want: cty.ObjectVal(map[string]cty.Value{ + "container": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "bar": cty.StringVal("baz"), + }), + cty.ObjectVal(map[string]cty.Value{ + "bar": cty.StringVal("boop"), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.ListVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "bar": cty.StringVal("beep value"), + }), + }), + }), + }), + }), + }, "nested fixup with dynamic block generation": { src: ` container { diff --git a/lang/blocktoattr/variables_test.go b/lang/blocktoattr/variables_test.go index 19f49a22b..ae469a064 100644 --- a/lang/blocktoattr/variables_test.go +++ b/lang/blocktoattr/variables_test.go @@ -77,6 +77,39 @@ foo { }, }, }, + "block syntax with nested blocks": { + src: ` +foo { + bar { + boop = baz + } +} +`, + schema: &configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "foo": { + Type: cty.List(cty.Object(map[string]cty.Type{ + "bar": cty.List(cty.Object(map[string]cty.Type{ + "boop": cty.String, + })), + })), + Optional: true, + }, + }, + }, + want: []hcl.Traversal{ + { + hcl.TraverseRoot{ + Name: "baz", + SrcRange: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 4, Column: 12, Byte: 26}, + End: hcl.Pos{Line: 4, Column: 15, Byte: 29}, + }, + }, + }, + }, + }, "dynamic block syntax": { src: ` dynamic "foo" {