From af0ff90d6ed217cbcad6a79da982178dcdd9ef9e Mon Sep 17 00:00:00 2001 From: Liam Cervante Date: Thu, 12 Jan 2023 17:02:29 +0100 Subject: [PATCH] Remove outputs from the jsonplan that are not from the root module (#32503) --- internal/command/jsonplan/plan.go | 9 +++ internal/command/jsonplan/plan_test.go | 96 ++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/internal/command/jsonplan/plan.go b/internal/command/jsonplan/plan.go index f045877847..908fff8db1 100644 --- a/internal/command/jsonplan/plan.go +++ b/internal/command/jsonplan/plan.go @@ -437,6 +437,15 @@ func (p *plan) marshalOutputChanges(changes *plans.Changes) error { p.OutputChanges = make(map[string]Change, len(changes.Outputs)) for _, oc := range changes.Outputs { + + // Skip output changes that are not from the root module. + // These are automatically stripped from plans that are written to disk + // elsewhere, we just need to duplicate the logic here in case anyone + // is converting this plan directly from memory. + if !oc.Addr.Module.IsRoot() { + continue + } + changeV, err := oc.Decode() if err != nil { return err diff --git a/internal/command/jsonplan/plan_test.go b/internal/command/jsonplan/plan_test.go index ef5b6cda24..e634ee3a33 100644 --- a/internal/command/jsonplan/plan_test.go +++ b/internal/command/jsonplan/plan_test.go @@ -7,6 +7,9 @@ import ( "github.com/google/go-cmp/cmp" "github.com/zclconf/go-cty/cty" + + "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/internal/plans" ) func TestOmitUnknowns(t *testing.T) { @@ -318,6 +321,99 @@ func TestEncodePaths(t *testing.T) { } } +func TestOutputs(t *testing.T) { + root := addrs.RootModuleInstance + + child, diags := addrs.ParseModuleInstanceStr("module.child") + if diags.HasErrors() { + t.Fatalf("unexpected errors: %s", diags.Err()) + } + + tests := map[string]struct { + changes *plans.Changes + expected map[string]Change + }{ + "copies all outputs": { + changes: &plans.Changes{ + Outputs: []*plans.OutputChangeSrc{ + { + Addr: root.OutputValue("first"), + ChangeSrc: plans.ChangeSrc{ + Action: plans.Create, + }, + }, + { + Addr: root.OutputValue("second"), + ChangeSrc: plans.ChangeSrc{ + Action: plans.Create, + }, + }, + }, + }, + expected: map[string]Change{ + "first": { + Actions: []string{"create"}, + Before: json.RawMessage("null"), + After: json.RawMessage("null"), + AfterUnknown: json.RawMessage("false"), + BeforeSensitive: json.RawMessage("false"), + AfterSensitive: json.RawMessage("false"), + }, + "second": { + Actions: []string{"create"}, + Before: json.RawMessage("null"), + After: json.RawMessage("null"), + AfterUnknown: json.RawMessage("false"), + BeforeSensitive: json.RawMessage("false"), + AfterSensitive: json.RawMessage("false"), + }, + }, + }, + "skips non root modules": { + changes: &plans.Changes{ + Outputs: []*plans.OutputChangeSrc{ + { + Addr: root.OutputValue("first"), + ChangeSrc: plans.ChangeSrc{ + Action: plans.Create, + }, + }, + { + Addr: child.OutputValue("second"), + ChangeSrc: plans.ChangeSrc{ + Action: plans.Create, + }, + }, + }, + }, + expected: map[string]Change{ + "first": { + Actions: []string{"create"}, + Before: json.RawMessage("null"), + After: json.RawMessage("null"), + AfterUnknown: json.RawMessage("false"), + BeforeSensitive: json.RawMessage("false"), + AfterSensitive: json.RawMessage("false"), + }, + }, + }, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { + p := newPlan() + + err := p.marshalOutputChanges(test.changes) + if err != nil { + t.Fatalf("unexpected err: %s", err) + } + + if !cmp.Equal(p.OutputChanges, test.expected) { + t.Errorf("wrong result:\n %v\n", cmp.Diff(p.OutputChanges, test.expected)) + } + }) + } +} + func deepObjectValue(depth int) cty.Value { v := cty.ObjectVal(map[string]cty.Value{ "a": cty.StringVal("a"),