add (forces new resource) to provider test diffs

Add the (forces new resource) annotation to the diff output for provider
tests failures when we can. This helps providers narrow down what might
be triggering changes when encountering test failures with the new SDK.
This commit is contained in:
James Bardin 2019-03-22 15:30:51 -04:00
parent 2e15f6f585
commit bb62aba651
3 changed files with 83 additions and 2 deletions

View File

@ -251,3 +251,26 @@ func pathFromFlatmapKeySet(key string, ty cty.Type) (cty.Path, error) {
// set as a whole changed. // set as a whole changed.
return nil, nil return nil, nil
} }
// FlatmapKeyFromPath returns the flatmap equivalent of the given cty.Path for
// use in generating legacy style diffs.
func FlatmapKeyFromPath(path cty.Path) string {
var parts []string
for _, step := range path {
switch step := step.(type) {
case cty.GetAttrStep:
parts = append(parts, step.Name)
case cty.IndexStep:
switch ty := step.Key.Type(); {
case ty == cty.String:
parts = append(parts, step.Key.AsString())
case ty == cty.Number:
i, _ := step.Key.AsBigFloat().Int64()
parts = append(parts, strconv.Itoa(int(i)))
}
}
}
return strings.Join(parts, ".")
}

View File

@ -3,6 +3,7 @@ package hcl2shim
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"strconv"
"strings" "strings"
"testing" "testing"
@ -365,5 +366,43 @@ func TestRequiresReplace(t *testing.T) {
}) })
} }
}
func TestFlatmapKeyFromPath(t *testing.T) {
for i, tc := range []struct {
path cty.Path
attr string
}{
{
path: cty.Path{
cty.GetAttrStep{Name: "force_new"},
},
attr: "force_new",
},
{
path: cty.Path{
cty.GetAttrStep{Name: "attr"},
cty.IndexStep{Key: cty.NumberIntVal(0)},
cty.GetAttrStep{Name: "force_new"},
},
attr: "attr.0.force_new",
},
{
path: cty.Path{
cty.GetAttrStep{Name: "attr"},
cty.IndexStep{Key: cty.StringVal("key")},
cty.GetAttrStep{Name: "obj_attr"},
cty.IndexStep{Key: cty.NumberIntVal(0)},
cty.GetAttrStep{Name: "force_new"},
},
attr: "attr.key.obj_attr.0.force_new",
},
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
attr := FlatmapKeyFromPath(tc.path)
if attr != tc.attr {
t.Fatalf("expected:%q got:%q", tc.attr, attr)
}
})
}
} }

View File

@ -214,6 +214,7 @@ func legacyDiffComparisonString(changes *plans.Changes) string {
} }
byModule := map[string]map[string]*ResourceChanges{} byModule := map[string]map[string]*ResourceChanges{}
resourceKeys := map[string][]string{} resourceKeys := map[string][]string{}
requiresReplace := map[string][]string{}
var moduleKeys []string var moduleKeys []string
for _, rc := range changes.Resources { for _, rc := range changes.Resources {
if rc.Action == plans.NoOp { if rc.Action == plans.NoOp {
@ -239,6 +240,12 @@ func legacyDiffComparisonString(changes *plans.Changes) string {
} else { } else {
byModule[moduleKey][resourceKey].Deposed[rc.DeposedKey] = rc byModule[moduleKey][resourceKey].Deposed[rc.DeposedKey] = rc
} }
rr := []string{}
for _, p := range rc.RequiredReplace.List() {
rr = append(rr, hcl2shim.FlatmapKeyFromPath(p))
}
requiresReplace[resourceKey] = rr
} }
sort.Strings(moduleKeys) sort.Strings(moduleKeys)
for _, ks := range resourceKeys { for _, ks := range resourceKeys {
@ -254,6 +261,8 @@ func legacyDiffComparisonString(changes *plans.Changes) string {
for _, resourceKey := range resourceKeys[moduleKey] { for _, resourceKey := range resourceKeys[moduleKey] {
rc := rcs[resourceKey] rc := rcs[resourceKey]
forceNewAttrs := requiresReplace[resourceKey]
crud := "UPDATE" crud := "UPDATE"
if rc.Current != nil { if rc.Current != nil {
switch rc.Current.Action { switch rc.Current.Action {
@ -341,7 +350,17 @@ func legacyDiffComparisonString(changes *plans.Changes) string {
// at the core layer. // at the core layer.
updateMsg := "" updateMsg := ""
// TODO: Mark " (forces new resource)" in updateMsg when appropriate.
// This may not be as precise as in the old diff, as it matches
// everything under the attribute that was originally marked as
// ForceNew, but should help make it easier to determine what
// caused replacement here.
for _, k := range forceNewAttrs {
if strings.HasPrefix(attrK, k) {
updateMsg = " (forces new resource)"
break
}
}
fmt.Fprintf( fmt.Fprintf(
&mBuf, " %s:%s %#v => %#v%s\n", &mBuf, " %s:%s %#v => %#v%s\n",