command/format: minor adjustments to plan rendering
This change makes various minor adjustments to the rendering of plans in the output of "terraform plan": - Resources are identified using the standard resource address syntax, rather than exposing the legacy internal representation used in the module diff resource keys. This fixes #8713. - Subjectively, having square brackets in the addresses made it look more visually "off" when the same name but with different indices were shown together with differing-length "symbols", so the symbols are now all padded and right-aligned to three characters for consistent layout across all operations. - The -/+ action is now more visually distinct, using several different colors to help communicate what it will do and including a more obvious "(new resource required)" marker to help draw attention to this not being just an update diff. This fixes #15350. - The resources are now sorted in a manner that sorts index [10] after index [9], rather than after index [1] as we did before. This makes it easier to scan the list and avoids the common confusion where it seems that there are only 10 items when in fact there are 11-20 items with all the tens hiding further up in the list.
This commit is contained in:
parent
53c0ff4017
commit
0dc6d97a37
|
@ -6,6 +6,7 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/config"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/colorstring"
|
||||
)
|
||||
|
@ -58,18 +59,27 @@ func formatPlanModuleExpand(
|
|||
return
|
||||
}
|
||||
|
||||
var moduleName string
|
||||
var modulePath []string
|
||||
if !m.IsRoot() {
|
||||
moduleName = fmt.Sprintf("module.%s", strings.Join(m.Path[1:], "."))
|
||||
modulePath = m.Path[1:]
|
||||
}
|
||||
|
||||
// We want to output the resources in sorted order to make things
|
||||
// easier to scan through, so get all the resource names and sort them.
|
||||
names := make([]string, 0, len(m.Resources))
|
||||
for name, _ := range m.Resources {
|
||||
addrs := map[string]*terraform.ResourceAddress{}
|
||||
for name := range m.Resources {
|
||||
names = append(names, name)
|
||||
var err error
|
||||
addrs[name], err = terraform.ParseResourceAddressForInstanceDiff(modulePath, name)
|
||||
if err != nil {
|
||||
// should never happen; indicates invalid diff
|
||||
panic("invalid resource address in diff")
|
||||
}
|
||||
}
|
||||
sort.Strings(names)
|
||||
sort.Slice(names, func(i, j int) bool {
|
||||
return addrs[names[i]].Less(addrs[names[j]])
|
||||
})
|
||||
|
||||
// Go through each sorted name and start building the output
|
||||
for _, name := range names {
|
||||
|
@ -78,25 +88,23 @@ func formatPlanModuleExpand(
|
|||
continue
|
||||
}
|
||||
|
||||
dataSource := strings.HasPrefix(name, "data.")
|
||||
|
||||
if moduleName != "" {
|
||||
name = moduleName + "." + name
|
||||
}
|
||||
addr := addrs[name]
|
||||
addrStr := addr.String()
|
||||
dataSource := addr.Mode == config.DataResourceMode
|
||||
|
||||
// Determine the color for the text (green for adding, yellow
|
||||
// for change, red for delete), and symbol, and output the
|
||||
// resource header.
|
||||
color := "yellow"
|
||||
symbol := "~"
|
||||
symbol := " ~"
|
||||
oldValues := true
|
||||
switch rdiff.ChangeType() {
|
||||
case terraform.DiffDestroyCreate:
|
||||
color = "green"
|
||||
symbol = "-/+"
|
||||
color = "yellow"
|
||||
symbol = "[red]-[reset]/[green]+[reset][yellow]"
|
||||
case terraform.DiffCreate:
|
||||
color = "green"
|
||||
symbol = "+"
|
||||
symbol = " +"
|
||||
oldValues = false
|
||||
|
||||
// If we're "creating" a data resource then we'll present it
|
||||
|
@ -106,12 +114,12 @@ func formatPlanModuleExpand(
|
|||
// to work with, so we need to cheat and exploit knowledge of the
|
||||
// naming scheme for data resources.
|
||||
if dataSource {
|
||||
symbol = "<="
|
||||
symbol = " <="
|
||||
color = "cyan"
|
||||
}
|
||||
case terraform.DiffDestroy:
|
||||
color = "red"
|
||||
symbol = "-"
|
||||
symbol = " -"
|
||||
}
|
||||
|
||||
var extraAttr []string
|
||||
|
@ -125,10 +133,13 @@ func formatPlanModuleExpand(
|
|||
if len(extraAttr) > 0 {
|
||||
extraStr = fmt.Sprintf(" (%s)", strings.Join(extraAttr, ", "))
|
||||
}
|
||||
if rdiff.ChangeType() == terraform.DiffDestroyCreate {
|
||||
extraStr = extraStr + opts.Color.Color(" [red][bold](new resource required)")
|
||||
}
|
||||
|
||||
buf.WriteString(opts.Color.Color(fmt.Sprintf(
|
||||
"[%s]%s %s%s\n",
|
||||
color, symbol, name, extraStr)))
|
||||
color, symbol, addrStr, extraStr)))
|
||||
|
||||
// Get all the attributes that are changing, and sort them. Also
|
||||
// determine the longest key so that we can align them all.
|
||||
|
@ -175,7 +186,7 @@ func formatPlanModuleExpand(
|
|||
u = attrDiff.Old
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(
|
||||
" %s:%s %#v => %#v%s\n",
|
||||
" %s:%s %#v => %#v%s\n",
|
||||
attrK,
|
||||
strings.Repeat(" ", keyLen-len(attrK)),
|
||||
u,
|
||||
|
@ -183,7 +194,7 @@ func formatPlanModuleExpand(
|
|||
updateMsg))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf(
|
||||
" %s:%s %#v%s\n",
|
||||
" %s:%s %#v%s\n",
|
||||
attrK,
|
||||
strings.Repeat(" ", keyLen-len(attrK)),
|
||||
v,
|
||||
|
|
|
@ -121,7 +121,7 @@ func TestPlan_rootDataSource(t *testing.T) {
|
|||
|
||||
expected := strings.TrimSpace(`
|
||||
<= data.type.name
|
||||
A: "B"
|
||||
A: "B"
|
||||
`)
|
||||
if actual != expected {
|
||||
t.Fatalf("expected:\n\n%s\n\ngot:\n\n%s", expected, actual)
|
||||
|
@ -162,7 +162,7 @@ func TestPlan_nestedDataSource(t *testing.T) {
|
|||
|
||||
expected := strings.TrimSpace(`
|
||||
<= module.nested.data.type.name
|
||||
A: "B"
|
||||
A: "B"
|
||||
`)
|
||||
if actual != expected {
|
||||
t.Fatalf("expected:\n\n%s\n\ngot:\n\n%s", expected, actual)
|
||||
|
|
Loading…
Reference in New Issue