-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve ValidationError Error() (#2056)
Improve ValidationError Error() to expose AttributePath. It appears that ValidationError is the bridge representation of any and all underlying TF Diagnostics. Allowing all the information to be printed can help save time when trying to understand unrecoverable error messages emitted from TF internals.
- Loading branch information
Showing
4 changed files
with
95 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,52 @@ | ||
package diagnostics | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
|
||
"github.com/hashicorp/go-cty/cty" | ||
) | ||
|
||
// ValidationError wraps validation errors reported by shims (currently shim v2 and tf5) | ||
// ValidationError wraps diagnostics reported by shims (currently shim v2 and tf5). | ||
type ValidationError struct { | ||
AttributePath cty.Path | ||
Summary string | ||
Detail string | ||
} | ||
|
||
// Last-resort error printout. | ||
// | ||
// To display nice error messages to Pulumi users the bridge should recognize ValidationError structs and reformat | ||
// AttributePath in terms of the Pulumi provider as appropriate, so this method should not be called on paths that are | ||
// expected to be user-visible. | ||
// | ||
// However this method is currently called in unrecoverable situations when underlying TF machinery fails. Opt to expose | ||
// all the information here to facilitate debugging. | ||
func (e ValidationError) Error() string { | ||
var buf bytes.Buffer | ||
if len(e.AttributePath) > 0 { | ||
fmt.Fprintf(&buf, "[") | ||
for i, p := range e.AttributePath { | ||
switch p := p.(type) { | ||
case cty.IndexStep: | ||
if p.Key.Type() == cty.String { | ||
fmt.Fprintf(&buf, "[%q]", p.Key.AsString()) | ||
} else if p.Key.Type() == cty.Number { | ||
fmt.Fprintf(&buf, "[%v]", p.Key.AsBigFloat().String()) | ||
} | ||
case cty.GetAttrStep: | ||
if i > 0 { | ||
fmt.Fprintf(&buf, ".") | ||
} | ||
fmt.Fprintf(&buf, p.Name) | ||
} | ||
} | ||
fmt.Fprintf(&buf, "] ") | ||
} | ||
if e.Detail != "" { | ||
return fmt.Sprintf("%s: %s", e.Summary, e.Detail) | ||
fmt.Fprintf(&buf, "%s: %s", e.Summary, e.Detail) | ||
} else { | ||
fmt.Fprintf(&buf, e.Summary) | ||
} | ||
return e.Summary | ||
return buf.String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package diagnostics | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/go-cty/cty" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestValidationError(t *testing.T) { | ||
type testCase struct { | ||
e ValidationError | ||
exp string | ||
} | ||
testCases := []testCase{ | ||
{ | ||
ValidationError{Summary: "Bad input"}, | ||
"Bad input", | ||
}, | ||
{ | ||
ValidationError{Summary: "Bad input", Detail: "the input is very bad"}, | ||
"Bad input: the input is very bad", | ||
}, | ||
{ | ||
ValidationError{Summary: "Bad input", AttributePath: cty.GetAttrPath("foo").IndexInt(0)}, | ||
"[foo[0]] Bad input", | ||
}, | ||
{ | ||
ValidationError{ | ||
Summary: "Bad input", | ||
Detail: "the input is very bad", | ||
AttributePath: cty.GetAttrPath("foo").IndexString("bar").GetAttr("baz"), | ||
}, | ||
"[foo[\"bar\"].baz] Bad input: the input is very bad", | ||
}, | ||
} | ||
for i, tc := range testCases { | ||
tc := tc | ||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { | ||
require.Equal(t, tc.exp, tc.e.Error()) | ||
}) | ||
} | ||
} |