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:
Martin Atkins 2017-06-21 18:38:33 -07:00
parent 53c0ff4017
commit 0dc6d97a37
2 changed files with 31 additions and 20 deletions

View File

@ -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,

View File

@ -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)