Skip to content

Commit 7a0444b

Browse files
committed
Improve error handling
1 parent 0f9ac8d commit 7a0444b

File tree

4 files changed

+44
-24
lines changed

4 files changed

+44
-24
lines changed

plugin/plugin.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func (RuleSetPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, er
3535
// In order to communicate the interface correctly with RPC,
3636
// the type of the related structure is registered in gob at the initial time.
3737
func init() {
38+
gob.Register(tflint.Error{})
3839
// https://github.com/hashicorp/hcl/blob/v2.0.0/hclsyntax/expression.go
3940
gob.Register(&hclsyntax.LiteralValueExpr{})
4041
gob.Register(&hclsyntax.ScopeTraversalExpr{})

tflint/client.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,24 @@ type AttributesRequest struct {
2828
AttributeName string
2929
}
3030

31+
// AttributesResponse is the interface used to communicate via RPC.
32+
type AttributesResponse struct {
33+
Attributes hcl.Attributes
34+
Err error
35+
}
36+
3137
// WalkResourceAttributes queries the host process, receives a list of attributes that match the conditions,
3238
// and passes each to the walker function.
3339
func (c *Client) WalkResourceAttributes(resource, attributeName string, walker func(*hcl.Attribute) error) error {
34-
var resp hcl.Attributes
35-
if err := c.rpcClient.Call("Plugin.Attributes", AttributesRequest{Resource: resource, AttributeName: attributeName}, &resp); err != nil {
40+
var response AttributesResponse
41+
if err := c.rpcClient.Call("Plugin.Attributes", AttributesRequest{Resource: resource, AttributeName: attributeName}, &response); err != nil {
3642
return err
3743
}
44+
if response.Err != nil {
45+
return response.Err
46+
}
3847

39-
for _, attribute := range resp {
48+
for _, attribute := range response.Attributes {
4049
if err := walker(attribute); err != nil {
4150
return err
4251
}
@@ -51,17 +60,26 @@ type EvalExprRequest struct {
5160
Ret interface{}
5261
}
5362

63+
// EvalExprResponse is the interface used to communicate with RPC.
64+
type EvalExprResponse struct {
65+
Val cty.Value
66+
Err error
67+
}
68+
5469
// EvaluateExpr queries the host process for the result of evaluating the value of the passed expression
5570
// and reflects it as the value of the second argument based on that.
5671
func (c *Client) EvaluateExpr(expr hcl.Expression, ret interface{}) error {
57-
var val cty.Value
72+
var response EvalExprResponse
5873
var err error
5974

60-
if err := c.rpcClient.Call("Plugin.EvalExpr", EvalExprRequest{Expr: expr, Ret: ret}, &val); err != nil {
75+
if err := c.rpcClient.Call("Plugin.EvalExpr", EvalExprRequest{Expr: expr, Ret: ret}, &response); err != nil {
6176
return err
6277
}
78+
if response.Err != nil {
79+
return response.Err
80+
}
6381

64-
err = gocty.FromCtyValue(val, ret)
82+
err = gocty.FromCtyValue(response.Val, ret)
6583
if err != nil {
6684
err := &Error{
6785
Code: TypeMismatchError,
@@ -110,7 +128,7 @@ func (*Client) EnsureNoError(err error, proc func() error) error {
110128
return proc()
111129
}
112130

113-
if appErr, ok := err.(*Error); ok {
131+
if appErr, ok := err.(Error); ok {
114132
switch appErr.Level {
115133
case WarningLevel:
116134
return nil

tflint/errors.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,43 @@ import "fmt"
44

55
const (
66
// EvaluationError is an error when interpolation failed (unexpected)
7-
EvaluationError int = 0
7+
EvaluationError string = "E:Evaluation"
88
// UnknownValueError is an error when an unknown value is referenced
9-
UnknownValueError int = 1 + iota
9+
UnknownValueError string = "W:UnknownValue"
1010
// NullValueError is an error when null value is referenced
11-
NullValueError
11+
NullValueError string = "W:NullValue"
1212
// TypeConversionError is an error when type conversion of cty.Value failed
13-
TypeConversionError
13+
TypeConversionError string = "E:TypeConversion"
1414
// TypeMismatchError is an error when a type of cty.Value is not as expected
15-
TypeMismatchError
15+
TypeMismatchError string = "E:TypeMismatch"
1616
// UnevaluableError is an error when a received expression has unevaluable references.
17-
UnevaluableError
17+
UnevaluableError string = "W:Unevaluable"
1818
// UnexpectedAttributeError is an error when handle unexpected attributes (e.g. block)
19-
UnexpectedAttributeError
19+
UnexpectedAttributeError string = "E:UnexpectedAttribute"
2020
// ExternalAPIError is an error when calling the external API (e.g. AWS SDK)
21-
ExternalAPIError
21+
ExternalAPIError string = "E:ExternalAPI"
22+
// ContextError is pseudo error code for propagating runtime context.
23+
ContextError string = "I:Context"
2224

2325
// FatalLevel is a recorverable error, it cause panic
24-
FatalLevel int = 0
26+
FatalLevel string = "Fatal"
2527
// ErrorLevel is a user-level error, it display and feedback error information
26-
ErrorLevel int = 1 + iota
28+
ErrorLevel string = "Error"
2729
// WarningLevel is a user-level warning. Although it is an error, it has no effect on execution.
28-
WarningLevel
30+
WarningLevel string = "Warning"
2931
)
3032

3133
// Error is application error object. It has own error code
3234
// for processing according to a type of error.
3335
type Error struct {
34-
Code int
35-
Level int
36+
Code string
37+
Level string
3638
Message string
3739
Cause error
3840
}
3941

4042
// Error shows error message. This must be implemented for error interface.
41-
func (e *Error) Error() string {
43+
func (e Error) Error() string {
4244
if e.Message != "" && e.Cause != nil {
4345
return fmt.Sprintf("%s; %s", e.Message, e.Cause)
4446
}

tflint/interface.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package tflint
22

33
import (
44
"github.com/hashicorp/hcl/v2"
5-
"github.com/zclconf/go-cty/cty"
65
)
76

87
// Runner acts as a client for each plugin to query the host process about the Terraform configurations.
@@ -24,7 +23,7 @@ type Rule interface {
2423

2524
// Server is the interface that hosts that provide the plugin mechanism must meet in order to respond to queries from the plugin.
2625
type Server interface {
27-
Attributes(*AttributesRequest, *hcl.Attributes) error
28-
EvalExpr(*EvalExprRequest, *cty.Value) error
26+
Attributes(*AttributesRequest, *AttributesResponse) error
27+
EvalExpr(*EvalExprRequest, *EvalExprResponse) error
2928
EmitIssue(*EmitIssueRequest, *interface{}) error
3029
}

0 commit comments

Comments
 (0)