From fbfb14142ed06cdf1f12a71b020dd5db4df868ea Mon Sep 17 00:00:00 2001 From: James Bardin Date: Mon, 16 Aug 2021 18:13:55 -0400 Subject: [PATCH] render empty nested containers as attributes Don't try to break down containers that are empty to render the diff, so we can avoid having to check for empty vs null in all cases. --- internal/command/format/diff.go | 25 ++++++++++++++++++-- internal/command/format/diff_test.go | 35 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/internal/command/format/diff.go b/internal/command/format/diff.go index b87b11c184..67aec91154 100644 --- a/internal/command/format/diff.go +++ b/internal/command/format/diff.go @@ -471,8 +471,28 @@ func (p *blockBodyDiffPrinter) writeAttrDiff(name string, attrS *configschema.At } if attrS.NestedType != nil { - p.writeNestedAttrDiff(name, attrS.NestedType, old, new, nameLen, indent, path, action, showJustNew) - return false + renderNested := true + + // If the collection values are empty or null, we render them as single attributes + switch attrS.NestedType.Nesting { + case configschema.NestingList, configschema.NestingSet, configschema.NestingMap: + var oldLen, newLen int + if !old.IsNull() && old.IsKnown() { + oldLen = old.LengthInt() + } + if !new.IsNull() && new.IsKnown() { + newLen = new.LengthInt() + } + + if oldLen+newLen == 0 { + renderNested = false + } + } + + if renderNested { + p.writeNestedAttrDiff(name, attrS.NestedType, old, new, nameLen, indent, path, action, showJustNew) + return false + } } p.buf.WriteString("\n") @@ -613,6 +633,7 @@ func (p *blockBodyDiffPrinter) writeNestedAttrDiff( allItems := make([]cty.Value, 0, len(oldItems)+len(newItems)) allItems = append(allItems, oldItems...) allItems = append(allItems, newItems...) + all := cty.SetVal(allItems) p.buf.WriteString(" = [") diff --git a/internal/command/format/diff_test.go b/internal/command/format/diff_test.go index 2b4ece8d2e..9775e7cbf5 100644 --- a/internal/command/format/diff_test.go +++ b/internal/command/format/diff_test.go @@ -2861,6 +2861,41 @@ func TestResourceChange_nestedSet(t *testing.T) { - volume_type = "gp2" -> null } } +`, + }, + "in-place update - empty nested sets": { + Action: plans.Update, + Mode: addrs.ManagedResourceMode, + Before: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("i-02ae66f368e8518a9"), + "ami": cty.StringVal("ami-BEFORE"), + "disks": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{ + "mount_point": cty.String, + "size": cty.String, + }))), + "root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{ + "volume_type": cty.String, + })), + }), + After: cty.ObjectVal(map[string]cty.Value{ + "id": cty.StringVal("i-02ae66f368e8518a9"), + "ami": cty.StringVal("ami-AFTER"), + "disks": cty.SetValEmpty(cty.Object(map[string]cty.Type{ + "mount_point": cty.String, + "size": cty.String, + })), + "root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{ + "volume_type": cty.String, + })), + }), + RequiredReplace: cty.NewPathSet(), + Schema: testSchema(configschema.NestingSet), + ExpectedOutput: ` # test_instance.example will be updated in-place + ~ resource "test_instance" "example" { + ~ ami = "ami-BEFORE" -> "ami-AFTER" + + disks = [] + id = "i-02ae66f368e8518a9" + } `, }, }