Skip to content

Commit 76cc991

Browse files
authored
Allow plugins to set host version constraints (#202)
1 parent eed3c18 commit 76cc991

File tree

11 files changed

+961
-642
lines changed

11 files changed

+961
-642
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/google/go-cmp v0.5.9
88
github.com/hashicorp/go-hclog v1.3.0
99
github.com/hashicorp/go-plugin v1.4.5
10+
github.com/hashicorp/go-version v1.6.0
1011
github.com/hashicorp/hcl/v2 v2.14.0
1112
github.com/zclconf/go-cty v1.11.0
1213
golang.org/x/tools v0.1.12

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ github.com/hashicorp/go-hclog v1.3.0 h1:G0ACM8Z2WilWgPv3Vdzwm3V0BQu/kSmrkVtpe1fy
4141
github.com/hashicorp/go-hclog v1.3.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
4242
github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo=
4343
github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
44+
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
45+
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
4446
github.com/hashicorp/hcl/v2 v2.14.0 h1:jX6+Q38Ly9zaAJlAjnFVyeNSNCKKW8D0wvyg7vij5Wc=
4547
github.com/hashicorp/hcl/v2 v2.14.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
4648
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=

plugin/fromproto/fromproto.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
99
"github.com/terraform-linters/tflint-plugin-sdk/plugin/proto"
1010
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
11+
"google.golang.org/grpc/codes"
1112
"google.golang.org/grpc/status"
1213
)
1314

@@ -251,7 +252,12 @@ func Error(err error) error {
251252
return err
252253
}
253254

254-
// If the error status has no details, retrieve an error from the gRPC error status.
255+
// Unimplemented is an unexpected error, so return as-is.
256+
if st.Code() == codes.Unimplemented {
257+
return err
258+
}
259+
260+
// If the error status has no details, return an error from the gRPC error status.
255261
// Remove the status code because some statuses are expected and should not be shown to users.
256262
if len(st.Details()) == 0 {
257263
return errors.New(st.Message())

plugin/host2plugin/client.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"os/exec"
66

77
"github.com/hashicorp/go-plugin"
8+
"github.com/hashicorp/go-version"
89
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
910
"github.com/terraform-linters/tflint-plugin-sdk/logger"
1011
"github.com/terraform-linters/tflint-plugin-sdk/plugin/fromproto"
@@ -67,6 +68,19 @@ func (c *GRPCClient) RuleNames() ([]string, error) {
6768
return resp.Names, nil
6869
}
6970

71+
// VersionConstraints returns constraints of TFLint versions.
72+
func (c *GRPCClient) VersionConstraints() (version.Constraints, error) {
73+
resp, err := c.client.GetVersionConstraint(context.Background(), &proto.GetVersionConstraint_Request{})
74+
if err != nil {
75+
return nil, fromproto.Error(err)
76+
}
77+
78+
if resp.Constraint == "" {
79+
return version.Constraints{}, nil
80+
}
81+
return version.NewConstraint(resp.Constraint)
82+
}
83+
7084
// ConfigSchema fetches the config schema from a plugin.
7185
func (c *GRPCClient) ConfigSchema() (*hclext.BodySchema, error) {
7286
resp, err := c.client.GetConfigSchema(context.Background(), &proto.GetConfigSchema_Request{})

plugin/host2plugin/host2plugin_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type mockRuleSet struct {
3737

3838
type mockRuleSetImpl struct {
3939
ruleNames func() []string
40+
versionConstraint func() string
4041
configSchema func() *hclext.BodySchema
4142
applyGlobalConfig func(*tflint.Config) error
4243
applyConfig func(*hclext.BodyContent) error
@@ -50,6 +51,13 @@ func (r *mockRuleSet) RuleNames() []string {
5051
return []string{}
5152
}
5253

54+
func (r *mockRuleSet) VersionConstraint() string {
55+
if r.impl.versionConstraint != nil {
56+
return r.impl.versionConstraint()
57+
}
58+
return ""
59+
}
60+
5361
func (r *mockRuleSet) ConfigSchema() *hclext.BodySchema {
5462
if r.impl.configSchema != nil {
5563
return r.impl.configSchema()
@@ -192,6 +200,60 @@ func TestRuleNames(t *testing.T) {
192200
}
193201
}
194202

203+
func TestVersionConstraints(t *testing.T) {
204+
// default error check helper
205+
neverHappend := func(err error) bool { return err != nil }
206+
207+
tests := []struct {
208+
Name string
209+
ServerImpl func() string
210+
Want string
211+
ErrCheck func(error) bool
212+
}{
213+
{
214+
Name: "default",
215+
ServerImpl: func() string {
216+
return ""
217+
},
218+
Want: "",
219+
ErrCheck: neverHappend,
220+
},
221+
{
222+
Name: "valid constraint",
223+
ServerImpl: func() string {
224+
return ">= 1.0"
225+
},
226+
Want: ">= 1.0",
227+
ErrCheck: neverHappend,
228+
},
229+
{
230+
Name: "invalid constraint",
231+
ServerImpl: func() string {
232+
return ">> 1.0"
233+
},
234+
Want: "",
235+
ErrCheck: func(err error) bool {
236+
return err == nil || err.Error() != "Malformed constraint: >> 1.0"
237+
},
238+
},
239+
}
240+
241+
for _, test := range tests {
242+
t.Run(test.Name, func(t *testing.T) {
243+
client := startTestGRPCPluginServer(t, newMockRuleSet("test_ruleset", "0.1.0", mockRuleSetImpl{versionConstraint: test.ServerImpl}))
244+
245+
got, err := client.VersionConstraints()
246+
if test.ErrCheck(err) {
247+
t.Fatalf("failed to call VersionConstraints: %s", err)
248+
}
249+
250+
if got.String() != test.Want {
251+
t.Errorf("want: %s, got: %s", test.Want, got)
252+
}
253+
})
254+
}
255+
}
256+
195257
func TestConfigSchema(t *testing.T) {
196258
// default error check helper
197259
neverHappend := func(err error) bool { return err != nil }

plugin/host2plugin/server.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ func (s *GRPCServer) GetRuleNames(ctx context.Context, req *proto.GetRuleNames_R
6363
return &proto.GetRuleNames_Response{Names: s.impl.RuleNames()}, nil
6464
}
6565

66+
// GetVersionConstraint returns a constraint of TFLint versions.
67+
func (s *GRPCServer) GetVersionConstraint(ctx context.Context, req *proto.GetVersionConstraint_Request) (*proto.GetVersionConstraint_Response, error) {
68+
return &proto.GetVersionConstraint_Response{Constraint: s.impl.VersionConstraint()}, nil
69+
}
70+
6671
// GetConfigSchema returns the config schema of the plugin.
6772
func (s *GRPCServer) GetConfigSchema(ctx context.Context, req *proto.GetConfigSchema_Request) (*proto.GetConfigSchema_Response, error) {
6873
return &proto.GetConfigSchema_Response{Schema: toproto.BodySchema(s.impl.ConfigSchema())}, nil

0 commit comments

Comments
 (0)