-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EnsureNoError
is a bad interface
#196
Comments
Type parameters in methods do not work... golang/go#49085 |
There is a way to check for known issues in rulesets instead of rules. Change the ruleset implementation as follows: func (r *BuiltinRuleSet) Check(runner Runner) error {
for _, rule := range r.EnabledRules {
if err := rule.Check(runner); err != nil {
if errors.Is(err, tflint.ErrUnevaluable) || errors.Is(err, tflint.ErrNullValue) || errors.Is(err, tflint.ErrUnknownValue) || errors.Is(err, tflint.ErrSensitive) {
continue
}
return fmt.Errorf("Failed to check `%s` rule: %s", rule.Name(), err)
}
}
return nil
} In this case, the rule can simply check for errors without using // Before
err := runner.EvaluteExpr(...)
err = runner.EnsureNoError(err, func () error {
// Do something
})
if err != nil {
return err
}
// After
err := runner.EvaluateExpr(...)
if err != nil {
return err
} However, we should be careful with early returns. An example like the following will unintentionally break prematurely: for _, expr := range expressions {
err := runner.EvaluateExpr(expr, ...)
if err != nil {
return err
}
} To avoid this, rules should join errors whenever possible. var errs []error
for _, expr := range expressions {
err := runner.EvaluateExpr(expr, ...)
if err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...) The ruleset unwraps the error and removes only the known errors: if err := rule.Check(runner); err != nil {
if errs, ok := err.(interface { Unwrap() []error }); ok {
var ers []error
for _, e := range errs.Unwrap() {
if errors.Is(err, tflint.ErrUnevaluable) || errors.Is(err, tflint.ErrNullValue) || errors.Is(err, tflint.ErrUnknownValue) || errors.Is(err, tflint.ErrSensitive) {
// skip
} else {
ers = append(ers, e)
}
}
err = errors.Join(ers...)
if err == nil {
continue
}
}
return fmt.Errorf("Failed to check `%s` rule: %s", rule.Name(), err)
} |
Or maybe the plugin developer should be aware of the known errors.
|
I made a modification to |
In TFLint, there are three patterns of expression evaluation results.
It was a difficult problem to handle these 3 results appropriately. The interface had to be designed so that plugin developers didn't know the details of the known issues and only knew if succeeded or failed.
EnsureNoError
was designed as a last resort. We made it a convention for developers to pass the error returned byEvaluateExpr
to this function. This aims to hide this problem by only calling the callback if no known issues occur.But this doesn't seem to work very well. By convention in Go, it is common to test the returned error by
if err != nil
, andEnsureNoError
is not intuitive. Therefore, it confuses developers as they don't know where this function is to use.We need a more intuitive interface. For example, with the type parameter added in Go 1.18, we can pass a callback function to be executed when the evaluation is successful to
EvaluateExpr
.The text was updated successfully, but these errors were encountered: