From c125397da1c7ff4384d58268b41100ce1c9df99c Mon Sep 17 00:00:00 2001 From: Liam Cervante Date: Thu, 12 Jan 2023 16:47:06 +0100 Subject: [PATCH] push the colorize actions as locally as possible (#32502) --- internal/command/jsonformat/computed/diff.go | 24 +++++++++-- .../jsonformat/computed/renderers/block.go | 16 +++---- .../jsonformat/computed/renderers/list.go | 16 +++---- .../jsonformat/computed/renderers/map.go | 12 +++--- .../jsonformat/computed/renderers/object.go | 12 +++--- .../computed/renderers/primitive.go | 42 +++++++++---------- .../computed/renderers/renderer_test.go | 7 +++- .../computed/renderers/sensitive.go | 8 ++-- .../computed/renderers/sensitive_block.go | 8 ++-- .../jsonformat/computed/renderers/set.go | 12 +++--- .../jsonformat/computed/renderers/string.go | 6 ++- .../computed/renderers/type_change.go | 2 +- .../jsonformat/computed/renderers/util.go | 26 +++++++----- 13 files changed, 109 insertions(+), 82 deletions(-) diff --git a/internal/command/jsonformat/computed/diff.go b/internal/command/jsonformat/computed/diff.go index 6ed057a4cc..79855d82e4 100644 --- a/internal/command/jsonformat/computed/diff.go +++ b/internal/command/jsonformat/computed/diff.go @@ -1,6 +1,10 @@ package computed -import "github.com/hashicorp/terraform/internal/plans" +import ( + "github.com/mitchellh/colorstring" + + "github.com/hashicorp/terraform/internal/plans" +) // Diff captures the computed diff for a single block, element or attribute. // @@ -52,18 +56,20 @@ func (diff Diff) RenderHuman(indent int, opts RenderHumanOpts) string { // // As with the RenderHuman function, the indent should only be applied on // multiline warnings and on the second and following lines. -func (diff Diff) WarningsHuman(indent int) []string { - return diff.Renderer.WarningsHuman(diff, indent) +func (diff Diff) WarningsHuman(indent int, opts RenderHumanOpts) []string { + return diff.Renderer.WarningsHuman(diff, indent, opts) } type DiffRenderer interface { RenderHuman(diff Diff, indent int, opts RenderHumanOpts) string - WarningsHuman(diff Diff, indent int) []string + WarningsHuman(diff Diff, indent int, opts RenderHumanOpts) []string } // RenderHumanOpts contains options that can control how the human render // function of the DiffRenderer will function. type RenderHumanOpts struct { + Colorize colorstring.Colorize + // OverrideNullSuffix tells the Renderer not to display the `-> null` suffix // that is normally displayed when an element, attribute, or block is // deleted. @@ -83,10 +89,20 @@ type RenderHumanOpts struct { ShowUnchangedChildren bool } +// NewRenderHumanOpts creates a new RenderHumanOpts struct with the required +// fields set. +func NewRenderHumanOpts(colorize colorstring.Colorize) RenderHumanOpts { + return RenderHumanOpts{ + Colorize: colorize, + } +} + // Clone returns a new RenderOpts object, that matches the original but can be // edited without changing the original. func (opts RenderHumanOpts) Clone() RenderHumanOpts { return RenderHumanOpts{ + Colorize: opts.Colorize, + OverrideNullSuffix: opts.OverrideNullSuffix, ShowUnchangedChildren: opts.ShowUnchangedChildren, diff --git a/internal/command/jsonformat/computed/renderers/block.go b/internal/command/jsonformat/computed/renderers/block.go index aa23fec31d..1cca3f0046 100644 --- a/internal/command/jsonformat/computed/renderers/block.go +++ b/internal/command/jsonformat/computed/renderers/block.go @@ -60,10 +60,10 @@ func (renderer blockRenderer) RenderHuman(diff computed.Diff, indent int, opts c sort.Strings(attributeKeys) var buf bytes.Buffer - buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts.OverrideForcesReplacement))) + buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts))) for _, importantKey := range importantAttributes { if attribute, ok := renderer.attributes[importantKey]; ok { - buf.WriteString(fmt.Sprintf("%s%s %-*s = %s\n", formatIndent(indent+1), format.DiffActionSymbol(attribute.Action), maximumAttributeKeyLen, importantKey, attribute.RenderHuman(indent+1, opts))) + buf.WriteString(fmt.Sprintf("%s%s %-*s = %s\n", formatIndent(indent+1), colorizeDiffAction(attribute.Action, opts), maximumAttributeKeyLen, importantKey, attribute.RenderHuman(indent+1, opts))) } } @@ -77,14 +77,14 @@ func (renderer blockRenderer) RenderHuman(diff computed.Diff, indent int, opts c continue } - for _, warning := range attribute.WarningsHuman(indent + 1) { + for _, warning := range attribute.WarningsHuman(indent+1, opts) { buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) } - buf.WriteString(fmt.Sprintf("%s%s %-*s = %s\n", formatIndent(indent+1), format.DiffActionSymbol(attribute.Action), maximumAttributeKeyLen, escapedAttributeKeys[key], attribute.RenderHuman(indent+1, opts))) + buf.WriteString(fmt.Sprintf("%s%s %-*s = %s\n", formatIndent(indent+1), colorizeDiffAction(attribute.Action, opts), maximumAttributeKeyLen, escapedAttributeKeys[key], attribute.RenderHuman(indent+1, opts))) } if unchangedAttributes > 0 { - buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("attribute", unchangedAttributes))) + buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("attribute", unchangedAttributes, opts))) } blockKeys := renderer.blocks.GetAllKeys() @@ -104,10 +104,10 @@ func (renderer blockRenderer) RenderHuman(diff computed.Diff, indent int, opts c foundChangedBlock = true } - for _, warning := range diff.WarningsHuman(indent + 1) { + for _, warning := range diff.WarningsHuman(indent+1, opts) { buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) } - buf.WriteString(fmt.Sprintf("%s%s %s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(diff.Action), ensureValidAttributeName(key), mapKey, diff.RenderHuman(indent+1, opts))) + buf.WriteString(fmt.Sprintf("%s%s %s%s %s\n", formatIndent(indent+1), colorizeDiffAction(diff.Action, opts), ensureValidAttributeName(key), mapKey, diff.RenderHuman(indent+1, opts))) } @@ -140,7 +140,7 @@ func (renderer blockRenderer) RenderHuman(diff computed.Diff, indent int, opts c } if unchangedBlocks > 0 { - buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("block", unchangedBlocks))) + buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("block", unchangedBlocks, opts))) } buf.WriteString(fmt.Sprintf("%s%s }", formatIndent(indent), format.DiffActionSymbol(plans.NoOp))) diff --git a/internal/command/jsonformat/computed/renderers/list.go b/internal/command/jsonformat/computed/renderers/list.go index c2ea303045..433f18ba89 100644 --- a/internal/command/jsonformat/computed/renderers/list.go +++ b/internal/command/jsonformat/computed/renderers/list.go @@ -33,7 +33,7 @@ type listRenderer struct { func (renderer listRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string { if len(renderer.elements) == 0 { - return fmt.Sprintf("[]%s%s", nullSuffix(opts.OverrideNullSuffix, diff.Action), forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("[]%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts)) } elementOpts := opts.Clone() @@ -50,7 +50,7 @@ func (renderer listRenderer) RenderHuman(diff computed.Diff, indent int, opts co renderNext := false var buf bytes.Buffer - buf.WriteString(fmt.Sprintf("[%s\n", forcesReplacement(diff.Replace, opts.OverrideForcesReplacement))) + buf.WriteString(fmt.Sprintf("[%s\n", forcesReplacement(diff.Replace, opts))) for _, element := range renderer.elements { if element.Action == plans.NoOp && !renderNext && !opts.ShowUnchangedChildren { unchangedElements = append(unchangedElements, element) @@ -70,14 +70,14 @@ func (renderer listRenderer) RenderHuman(diff computed.Diff, indent int, opts co // minus 1 as the most recent unchanged element will be printed out // in full. if len(unchangedElements) > 1 { - buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("element", len(unchangedElements)-1))) + buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("element", len(unchangedElements)-1, opts))) } // If our list of unchanged elements contains at least one entry, // we're going to print out the most recent change in full. That's // what happens here. if len(unchangedElements) > 0 { lastElement := unchangedElements[len(unchangedElements)-1] - buf.WriteString(fmt.Sprintf("%s%s %s,\n", formatIndent(indent+1), format.DiffActionSymbol(lastElement.Action), lastElement.RenderHuman(indent+1, unchangedElementOpts))) + buf.WriteString(fmt.Sprintf("%s%s %s,\n", formatIndent(indent+1), colorizeDiffAction(lastElement.Action, opts), lastElement.RenderHuman(indent+1, unchangedElementOpts))) } // We now reset the unchanged elements list, we've printed out a // count of all the elements we skipped so we start counting from @@ -95,10 +95,10 @@ func (renderer listRenderer) RenderHuman(diff computed.Diff, indent int, opts co renderNext = element.Action != plans.NoOp } - for _, warning := range element.WarningsHuman(indent + 1) { + for _, warning := range element.WarningsHuman(indent+1, opts) { buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) } - buf.WriteString(fmt.Sprintf("%s%s %s,\n", formatIndent(indent+1), format.DiffActionSymbol(element.Action), element.RenderHuman(indent+1, elementOpts))) + buf.WriteString(fmt.Sprintf("%s%s %s,\n", formatIndent(indent+1), colorizeDiffAction(element.Action, opts), element.RenderHuman(indent+1, elementOpts))) } // If we were not displaying any context alongside our changes then the @@ -108,9 +108,9 @@ func (renderer listRenderer) RenderHuman(diff computed.Diff, indent int, opts co // If we were displaying context, then this will contain any unchanged // elements since our last change, so we should also print it out. if len(unchangedElements) > 0 { - buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("element", len(unchangedElements)))) + buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("element", len(unchangedElements), opts))) } - buf.WriteString(fmt.Sprintf("%s%s ]%s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), nullSuffix(opts.OverrideNullSuffix, diff.Action))) + buf.WriteString(fmt.Sprintf("%s%s ]%s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), nullSuffix(diff.Action, opts))) return buf.String() } diff --git a/internal/command/jsonformat/computed/renderers/map.go b/internal/command/jsonformat/computed/renderers/map.go index 71342f4be7..e4c3b9b5e9 100644 --- a/internal/command/jsonformat/computed/renderers/map.go +++ b/internal/command/jsonformat/computed/renderers/map.go @@ -36,7 +36,7 @@ type mapRenderer struct { func (renderer mapRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string { if len(renderer.elements) == 0 { - return fmt.Sprintf("{}%s%s", nullSuffix(opts.OverrideNullSuffix, diff.Action), forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("{}%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts)) } unchangedElements := 0 @@ -55,7 +55,7 @@ func (renderer mapRenderer) RenderHuman(diff computed.Diff, indent int, opts com } var buf bytes.Buffer - buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts.OverrideForcesReplacement))) + buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts))) for _, key := range keys { element := renderer.elements[key] @@ -65,7 +65,7 @@ func (renderer mapRenderer) RenderHuman(diff computed.Diff, indent int, opts com continue } - for _, warning := range element.WarningsHuman(indent + 1) { + for _, warning := range element.WarningsHuman(indent+1, opts) { buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) } @@ -79,13 +79,13 @@ func (renderer mapRenderer) RenderHuman(diff computed.Diff, indent int, opts com // additional 2 characters, as we are going to add quotation marks ("") // around the key when it is rendered. keyLenWithOffset := renderer.maximumKeyLen + 2 - buf.WriteString(fmt.Sprintf("%s%s %-*q = %s%s\n", formatIndent(indent+1), format.DiffActionSymbol(element.Action), keyLenWithOffset, key, element.RenderHuman(indent+1, elementOpts), comma)) + buf.WriteString(fmt.Sprintf("%s%s %-*q = %s%s\n", formatIndent(indent+1), colorizeDiffAction(element.Action, opts), keyLenWithOffset, key, element.RenderHuman(indent+1, elementOpts), comma)) } if unchangedElements > 0 { - buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("element", unchangedElements))) + buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("element", unchangedElements, opts))) } - buf.WriteString(fmt.Sprintf("%s%s }%s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), nullSuffix(opts.OverrideNullSuffix, diff.Action))) + buf.WriteString(fmt.Sprintf("%s%s }%s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), nullSuffix(diff.Action, opts))) return buf.String() } diff --git a/internal/command/jsonformat/computed/renderers/object.go b/internal/command/jsonformat/computed/renderers/object.go index 786d646da8..1ff873bbeb 100644 --- a/internal/command/jsonformat/computed/renderers/object.go +++ b/internal/command/jsonformat/computed/renderers/object.go @@ -35,7 +35,7 @@ type objectRenderer struct { func (renderer objectRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string { if len(renderer.attributes) == 0 { - return fmt.Sprintf("{}%s%s", nullSuffix(opts.OverrideNullSuffix, diff.Action), forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("{}%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts)) } attributeOpts := opts.Clone() @@ -60,7 +60,7 @@ func (renderer objectRenderer) RenderHuman(diff computed.Diff, indent int, opts unchangedAttributes := 0 var buf bytes.Buffer - buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts.OverrideForcesReplacement))) + buf.WriteString(fmt.Sprintf("{%s\n", forcesReplacement(diff.Replace, opts))) for _, key := range keys { attribute := renderer.attributes[key] @@ -70,16 +70,16 @@ func (renderer objectRenderer) RenderHuman(diff computed.Diff, indent int, opts continue } - for _, warning := range attribute.WarningsHuman(indent + 1) { + for _, warning := range attribute.WarningsHuman(indent+1, opts) { buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) } - buf.WriteString(fmt.Sprintf("%s%s %-*s = %s\n", formatIndent(indent+1), format.DiffActionSymbol(attribute.Action), maximumKeyLen, escapedKeys[key], attribute.RenderHuman(indent+1, attributeOpts))) + buf.WriteString(fmt.Sprintf("%s%s %-*s = %s\n", formatIndent(indent+1), colorizeDiffAction(attribute.Action, opts), maximumKeyLen, escapedKeys[key], attribute.RenderHuman(indent+1, attributeOpts))) } if unchangedAttributes > 0 { - buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("attribute", unchangedAttributes))) + buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("attribute", unchangedAttributes, opts))) } - buf.WriteString(fmt.Sprintf("%s%s }%s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), nullSuffix(opts.OverrideNullSuffix, diff.Action))) + buf.WriteString(fmt.Sprintf("%s%s }%s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), nullSuffix(diff.Action, opts))) return buf.String() } diff --git a/internal/command/jsonformat/computed/renderers/primitive.go b/internal/command/jsonformat/computed/renderers/primitive.go index 95d076ccbe..baa57d0ab1 100644 --- a/internal/command/jsonformat/computed/renderers/primitive.go +++ b/internal/command/jsonformat/computed/renderers/primitive.go @@ -35,24 +35,24 @@ func (renderer primitiveRenderer) RenderHuman(diff computed.Diff, indent int, op return renderer.renderStringDiff(diff, indent, opts) } - beforeValue := renderPrimitiveValue(renderer.before, renderer.ctype) - afterValue := renderPrimitiveValue(renderer.after, renderer.ctype) + beforeValue := renderPrimitiveValue(renderer.before, renderer.ctype, opts) + afterValue := renderPrimitiveValue(renderer.after, renderer.ctype, opts) switch diff.Action { case plans.Create: - return fmt.Sprintf("%s%s", afterValue, forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("%s%s", afterValue, forcesReplacement(diff.Replace, opts)) case plans.Delete: - return fmt.Sprintf("%s%s%s", beforeValue, nullSuffix(opts.OverrideNullSuffix, diff.Action), forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("%s%s%s", beforeValue, nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts)) case plans.NoOp: - return fmt.Sprintf("%s%s", beforeValue, forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("%s%s", beforeValue, forcesReplacement(diff.Replace, opts)) default: - return fmt.Sprintf("%s [yellow]->[reset] %s%s", beforeValue, afterValue, forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("%s %s %s%s", beforeValue, opts.Colorize.Color("[yellow]->[reset]"), afterValue, forcesReplacement(diff.Replace, opts)) } } -func renderPrimitiveValue(value interface{}, t cty.Type) string { +func renderPrimitiveValue(value interface{}, t cty.Type, opts computed.RenderHumanOpts) string { if value == nil { - return "[dark_gray]null[reset]" + return opts.Colorize.Color("[dark_gray]null[reset]") } switch { @@ -75,7 +75,7 @@ func (renderer primitiveRenderer) renderStringDiff(diff computed.Diff, indent in switch diff.Action { case plans.Create, plans.NoOp: - str := evaluatePrimitiveString(renderer.after) + str := evaluatePrimitiveString(renderer.after, opts) if str.Json != nil { if diff.Action == plans.NoOp { @@ -86,7 +86,7 @@ func (renderer primitiveRenderer) renderStringDiff(diff computed.Diff, indent in } if !str.IsMultiline { - return fmt.Sprintf("%q%s", str.String, forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("%q%s", str.String, forcesReplacement(diff.Replace, opts)) } // We are creating a single multiline string, so let's split by the new @@ -99,14 +99,14 @@ func (renderer primitiveRenderer) renderStringDiff(diff computed.Diff, indent in // beginning of the first line. lines[0] = fmt.Sprintf("%s%s %s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), lines[0]) case plans.Delete: - str := evaluatePrimitiveString(renderer.before) + str := evaluatePrimitiveString(renderer.before, opts) if str.Json != nil { return renderer.renderStringDiffAsJson(diff, indent, opts, str, evaluatedString{}) } if !str.IsMultiline { - return fmt.Sprintf("%q%s%s", str.String, nullSuffix(opts.OverrideNullSuffix, diff.Action), forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("%q%s%s", str.String, nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts)) } // We are creating a single multiline string, so let's split by the new @@ -119,8 +119,8 @@ func (renderer primitiveRenderer) renderStringDiff(diff computed.Diff, indent in // beginning of the first line. lines[0] = fmt.Sprintf("%s%s %s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), lines[0]) default: - beforeString := evaluatePrimitiveString(renderer.before) - afterString := evaluatePrimitiveString(renderer.after) + beforeString := evaluatePrimitiveString(renderer.before, opts) + afterString := evaluatePrimitiveString(renderer.after, opts) if beforeString.Json != nil && afterString.Json != nil { return renderer.renderStringDiffAsJson(diff, indent, opts, beforeString, afterString) @@ -139,7 +139,7 @@ func (renderer primitiveRenderer) renderStringDiff(diff computed.Diff, indent in } if !beforeString.IsMultiline && !afterString.IsMultiline { - return fmt.Sprintf("%q [yellow]->[reset] %q%s", beforeString.String, afterString.String, forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("%q %s %q%s", beforeString.String, opts.Colorize.Color("[yellow]->[reset]"), afterString.String, forcesReplacement(diff.Replace, opts)) } beforeLines := strings.Split(beforeString.String, "\n") @@ -147,12 +147,12 @@ func (renderer primitiveRenderer) renderStringDiff(diff computed.Diff, indent in processIndices := func(beforeIx, afterIx int) { if beforeIx < 0 || beforeIx >= len(beforeLines) { - lines = append(lines, fmt.Sprintf("%s%s %s", formatIndent(indent), format.DiffActionSymbol(plans.Create), afterLines[afterIx])) + lines = append(lines, fmt.Sprintf("%s%s %s", formatIndent(indent), colorizeDiffAction(plans.Create, opts), afterLines[afterIx])) return } if afterIx < 0 || afterIx >= len(afterLines) { - lines = append(lines, fmt.Sprintf("%s%s %s", formatIndent(indent), format.DiffActionSymbol(plans.Delete), beforeLines[beforeIx])) + lines = append(lines, fmt.Sprintf("%s%s %s", formatIndent(indent), colorizeDiffAction(plans.Delete, opts), beforeLines[beforeIx])) return } @@ -168,10 +168,10 @@ func (renderer primitiveRenderer) renderStringDiff(diff computed.Diff, indent in // We return early if we find non-multiline strings or JSON strings, so we // know here that we just render the lines slice properly. return fmt.Sprintf("<<-EOT%s\n%s\n%sEOT%s", - forcesReplacement(diff.Replace, opts.OverrideForcesReplacement), + forcesReplacement(diff.Replace, opts), strings.Join(lines, "\n"), formatIndent(indent), - nullSuffix(opts.OverrideNullSuffix, diff.Action)) + nullSuffix(diff.Action, opts)) } func (renderer primitiveRenderer) renderStringDiffAsJson(diff computed.Diff, indent int, opts computed.RenderHumanOpts, before evaluatedString, after evaluatedString) string { @@ -191,13 +191,13 @@ func (renderer primitiveRenderer) renderStringDiffAsJson(diff computed.Diff, ind } else { // We only show the replace suffix if we didn't print something out // about whitespace changes. - replace = forcesReplacement(diff.Replace, opts.OverrideForcesReplacement) + replace = forcesReplacement(diff.Replace, opts) } renderedJsonDiff := jsonDiff.RenderHuman(indent, opts) if strings.Contains(renderedJsonDiff, "\n") { - return fmt.Sprintf("jsonencode(%s\n%s%s %s%s\n%s)", whitespace, formatIndent(indent), format.DiffActionSymbol(diff.Action), renderedJsonDiff, replace, formatIndent(indent)) + return fmt.Sprintf("jsonencode(%s\n%s%s %s%s\n%s)", whitespace, formatIndent(indent), colorizeDiffAction(diff.Action, opts), renderedJsonDiff, replace, formatIndent(indent)) } return fmt.Sprintf("jsonencode(%s)%s%s", renderedJsonDiff, whitespace, replace) } diff --git a/internal/command/jsonformat/computed/renderers/renderer_test.go b/internal/command/jsonformat/computed/renderers/renderer_test.go index 0fd1e9845b..d57581cc7c 100644 --- a/internal/command/jsonformat/computed/renderers/renderer_test.go +++ b/internal/command/jsonformat/computed/renderers/renderer_test.go @@ -1996,12 +1996,15 @@ EOT } for name, tc := range tcs { t.Run(name, func(t *testing.T) { + + opts := tc.opts.Clone() + opts.Colorize = colorize + expected := strings.TrimSpace(tc.expected) - actual := colorize.Color(tc.diff.RenderHuman(0, tc.opts)) + actual := tc.diff.RenderHuman(0, opts) if diff := cmp.Diff(expected, actual); len(diff) > 0 { t.Fatalf("\nexpected:\n%s\nactual:\n%s\ndiff:\n%s\n", expected, actual, diff) } }) } - } diff --git a/internal/command/jsonformat/computed/renderers/sensitive.go b/internal/command/jsonformat/computed/renderers/sensitive.go index 873c5e0539..a24040cc6b 100644 --- a/internal/command/jsonformat/computed/renderers/sensitive.go +++ b/internal/command/jsonformat/computed/renderers/sensitive.go @@ -25,10 +25,10 @@ type sensitiveRenderer struct { } func (renderer sensitiveRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string { - return fmt.Sprintf("(sensitive)%s%s", nullSuffix(opts.OverrideNullSuffix, diff.Action), forcesReplacement(diff.Replace, opts.OverrideForcesReplacement)) + return fmt.Sprintf("(sensitive)%s%s", nullSuffix(diff.Action, opts), forcesReplacement(diff.Replace, opts)) } -func (renderer sensitiveRenderer) WarningsHuman(diff computed.Diff, indent int) []string { +func (renderer sensitiveRenderer) WarningsHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) []string { if (renderer.beforeSensitive == renderer.afterSensitive) || renderer.inner.Action == plans.Create || renderer.inner.Action == plans.Delete { // Only display warnings for sensitive values if they are changing from // being sensitive or to being sensitive and if they are not being @@ -38,9 +38,9 @@ func (renderer sensitiveRenderer) WarningsHuman(diff computed.Diff, indent int) var warning string if renderer.beforeSensitive { - warning = fmt.Sprintf(" # [yellow]Warning[reset]: this attribute value will no longer be marked as sensitive\n%s # after applying this change.", formatIndent(indent)) + warning = opts.Colorize.Color(fmt.Sprintf(" # [yellow]Warning[reset]: this attribute value will no longer be marked as sensitive\n%s # after applying this change.", formatIndent(indent))) } else { - warning = fmt.Sprintf(" # [yellow]Warning[reset]: this attribute value will be marked as sensitive and will not\n%s # display in UI output after applying this change.", formatIndent(indent)) + warning = opts.Colorize.Color(fmt.Sprintf(" # [yellow]Warning[reset]: this attribute value will be marked as sensitive and will not\n%s # display in UI output after applying this change.", formatIndent(indent))) } if renderer.inner.Action == plans.NoOp { diff --git a/internal/command/jsonformat/computed/renderers/sensitive_block.go b/internal/command/jsonformat/computed/renderers/sensitive_block.go index 07cf465cfe..22abb333a2 100644 --- a/internal/command/jsonformat/computed/renderers/sensitive_block.go +++ b/internal/command/jsonformat/computed/renderers/sensitive_block.go @@ -26,10 +26,10 @@ type sensitiveBlockRenderer struct { func (renderer sensitiveBlockRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string { cachedLinePrefix := fmt.Sprintf("%s%s ", formatIndent(indent), format.DiffActionSymbol(plans.NoOp)) return fmt.Sprintf("{%s\n%s # At least one attribute in this block is (or was) sensitive,\n%s # so its contents will not be displayed.\n%s}", - forcesReplacement(diff.Replace, opts.OverrideForcesReplacement), cachedLinePrefix, cachedLinePrefix, cachedLinePrefix) + forcesReplacement(diff.Replace, opts), cachedLinePrefix, cachedLinePrefix, cachedLinePrefix) } -func (renderer sensitiveBlockRenderer) WarningsHuman(diff computed.Diff, indent int) []string { +func (renderer sensitiveBlockRenderer) WarningsHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) []string { if (renderer.beforeSensitive == renderer.afterSensitive) || renderer.inner.Action == plans.Create || renderer.inner.Action == plans.Delete { // Only display warnings for sensitive values if they are changing from // being sensitive or to being sensitive and if they are not being @@ -39,9 +39,9 @@ func (renderer sensitiveBlockRenderer) WarningsHuman(diff computed.Diff, indent var warning string if renderer.beforeSensitive { - warning = fmt.Sprintf(" # [yellow]Warning[reset]: this block will no longer be marked as sensitive\n%s # after applying this change.", formatIndent(indent)) + warning = opts.Colorize.Color(fmt.Sprintf(" # [yellow]Warning[reset]: this block will no longer be marked as sensitive\n%s # after applying this change.", formatIndent(indent))) } else { - warning = fmt.Sprintf(" # [yellow]Warning[reset]: this block will be marked as sensitive and will not\n%s # display in UI output after applying this change.", formatIndent(indent)) + warning = opts.Colorize.Color(fmt.Sprintf(" # [yellow]Warning[reset]: this block will be marked as sensitive and will not\n%s # display in UI output after applying this change.", formatIndent(indent))) } if renderer.inner.Action == plans.NoOp { diff --git a/internal/command/jsonformat/computed/renderers/set.go b/internal/command/jsonformat/computed/renderers/set.go index ccf8d66a58..c01cfeed6a 100644 --- a/internal/command/jsonformat/computed/renderers/set.go +++ b/internal/command/jsonformat/computed/renderers/set.go @@ -41,7 +41,7 @@ func (renderer setRenderer) RenderHuman(diff computed.Diff, indent int, opts com displayForcesReplacementInChildren := diff.Replace && renderer.overrideForcesReplacement if len(renderer.elements) == 0 { - return fmt.Sprintf("[]%s%s", nullSuffix(opts.OverrideNullSuffix, diff.Action), forcesReplacement(displayForcesReplacementInSelf, opts.OverrideForcesReplacement)) + return fmt.Sprintf("[]%s%s", nullSuffix(diff.Action, opts), forcesReplacement(displayForcesReplacementInSelf, opts)) } elementOpts := opts.Clone() @@ -51,23 +51,23 @@ func (renderer setRenderer) RenderHuman(diff computed.Diff, indent int, opts com unchangedElements := 0 var buf bytes.Buffer - buf.WriteString(fmt.Sprintf("[%s\n", forcesReplacement(displayForcesReplacementInSelf, opts.OverrideForcesReplacement))) + buf.WriteString(fmt.Sprintf("[%s\n", forcesReplacement(displayForcesReplacementInSelf, opts))) for _, element := range renderer.elements { if element.Action == plans.NoOp && !opts.ShowUnchangedChildren { unchangedElements++ continue } - for _, warning := range element.WarningsHuman(indent + 1) { + for _, warning := range element.WarningsHuman(indent+1, opts) { buf.WriteString(fmt.Sprintf("%s%s\n", formatIndent(indent+1), warning)) } - buf.WriteString(fmt.Sprintf("%s%s %s,\n", formatIndent(indent+1), format.DiffActionSymbol(element.Action), element.RenderHuman(indent+1, elementOpts))) + buf.WriteString(fmt.Sprintf("%s%s %s,\n", formatIndent(indent+1), colorizeDiffAction(element.Action, opts), element.RenderHuman(indent+1, elementOpts))) } if unchangedElements > 0 { - buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("element", unchangedElements))) + buf.WriteString(fmt.Sprintf("%s%s %s\n", formatIndent(indent+1), format.DiffActionSymbol(plans.NoOp), unchanged("element", unchangedElements, opts))) } - buf.WriteString(fmt.Sprintf("%s%s ]%s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), nullSuffix(opts.OverrideNullSuffix, diff.Action))) + buf.WriteString(fmt.Sprintf("%s%s ]%s", formatIndent(indent), format.DiffActionSymbol(plans.NoOp), nullSuffix(diff.Action, opts))) return buf.String() } diff --git a/internal/command/jsonformat/computed/renderers/string.go b/internal/command/jsonformat/computed/renderers/string.go index 4efc594306..91fbd62059 100644 --- a/internal/command/jsonformat/computed/renderers/string.go +++ b/internal/command/jsonformat/computed/renderers/string.go @@ -3,6 +3,8 @@ package renderers import ( "encoding/json" "strings" + + "github.com/hashicorp/terraform/internal/command/jsonformat/computed" ) type evaluatedString struct { @@ -12,9 +14,9 @@ type evaluatedString struct { IsMultiline bool } -func evaluatePrimitiveString(value interface{}) evaluatedString { +func evaluatePrimitiveString(value interface{}, opts computed.RenderHumanOpts) evaluatedString { if value == nil { - return evaluatedString{String: "[dark_gray]null[reset]"} + return evaluatedString{String: opts.Colorize.Color("[dark_gray]null[reset]")} } str := value.(string) diff --git a/internal/command/jsonformat/computed/renderers/type_change.go b/internal/command/jsonformat/computed/renderers/type_change.go index 8e72a82c5c..7469b51be6 100644 --- a/internal/command/jsonformat/computed/renderers/type_change.go +++ b/internal/command/jsonformat/computed/renderers/type_change.go @@ -24,5 +24,5 @@ type typeChangeRenderer struct { func (renderer typeChangeRenderer) RenderHuman(diff computed.Diff, indent int, opts computed.RenderHumanOpts) string { opts.OverrideNullSuffix = true // Never render null suffix for children of type changes. - return fmt.Sprintf("%s [yellow]->[reset] %s", renderer.before.RenderHuman(indent, opts), renderer.after.RenderHuman(indent, opts)) + return fmt.Sprintf("%s %s %s", renderer.before.RenderHuman(indent, opts), opts.Colorize.Color("[yellow]->[reset]"), renderer.after.RenderHuman(indent, opts)) } diff --git a/internal/command/jsonformat/computed/renderers/util.go b/internal/command/jsonformat/computed/renderers/util.go index 90d901be12..5ba8dd437d 100644 --- a/internal/command/jsonformat/computed/renderers/util.go +++ b/internal/command/jsonformat/computed/renderers/util.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" + "github.com/hashicorp/terraform/internal/command/format" + "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/hashicorp/terraform/internal/command/jsonformat/computed" @@ -16,24 +18,24 @@ import ( type NoWarningsRenderer struct{} // WarningsHuman returns an empty slice, as the name NoWarningsRenderer suggests. -func (render NoWarningsRenderer) WarningsHuman(diff computed.Diff, indent int) []string { +func (render NoWarningsRenderer) WarningsHuman(_ computed.Diff, _ int, _ computed.RenderHumanOpts) []string { return nil } // nullSuffix returns the `-> null` suffix if the change is a delete action, and // it has not been overridden. -func nullSuffix(override bool, action plans.Action) string { - if !override && action == plans.Delete { - return " [dark_gray]-> null[reset]" +func nullSuffix(action plans.Action, opts computed.RenderHumanOpts) string { + if !opts.OverrideNullSuffix && action == plans.Delete { + return opts.Colorize.Color(" [dark_gray]-> null[reset]") } return "" } // forcesReplacement returns the `# forces replacement` suffix if this change is // driving the entire resource to be replaced. -func forcesReplacement(replace bool, override bool) string { - if replace || override { - return " [red]# forces replacement[reset]" +func forcesReplacement(replace bool, opts computed.RenderHumanOpts) string { + if replace || opts.OverrideForcesReplacement { + return opts.Colorize.Color(" [red]# forces replacement[reset]") } return "" } @@ -46,11 +48,11 @@ func formatIndent(indent int) string { // unchanged prints out a description saying how many of 'keyword' have been // hidden because they are unchanged or noop actions. -func unchanged(keyword string, count int) string { +func unchanged(keyword string, count int, opts computed.RenderHumanOpts) string { if count == 1 { - return fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", count, keyword) + return opts.Colorize.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %s hidden)[reset]", count, keyword)) } - return fmt.Sprintf("[dark_gray]# (%d unchanged %ss hidden)[reset]", count, keyword) + return opts.Colorize.Color(fmt.Sprintf("[dark_gray]# (%d unchanged %ss hidden)[reset]", count, keyword)) } // ensureValidAttributeName checks if `name` contains any HCL syntax and returns @@ -61,3 +63,7 @@ func ensureValidAttributeName(name string) string { } return name } + +func colorizeDiffAction(action plans.Action, opts computed.RenderHumanOpts) string { + return opts.Colorize.Color(format.DiffActionSymbol(action)) +}