Skip to content

Commit 5f397e1

Browse files
authored
Merge pull request #38 from terraform-linters/revise_package_structure
Revise package structure
2 parents c5fcef3 + 44efc8d commit 5f397e1

23 files changed

+541
-431
lines changed

helper/doc.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Package helper contains implementations for plugin testing.
2+
//
3+
// You can test the implemented rules using the mock Runner that is not
4+
// an RPC client. It is similar to TFLint's Runner, but is implemented
5+
// from scratch to avoid Terraform dependencies.
6+
//
7+
// Some implementations of the mock Runner have been simplified. As a result,
8+
// note that some features may not behave exactly as they should.
9+
package helper

helper/issue.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import (
66
)
77

88
// Issue is a stub that has the same structure as the actually used issue object.
9-
// This is only used for testing, as the Runner client doesn't depend on the actual Issue structure.
9+
// This is only used for testing, as the mock Runner doesn't depend on the actual Issue structure.
1010
type Issue struct {
1111
Rule tflint.Rule
1212
Message string
1313
Range hcl.Range
1414
}
1515

16-
// Issues is a list of Issue
16+
// Issues is a list of Issue.
1717
type Issues []*Issue

helper/runner.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ import (
88
"github.com/zclconf/go-cty/cty/gocty"
99
)
1010

11-
// Runner is a pseudo Runner client provided for plugin testing.
12-
// Actually, it is provided as an RPC client, but for the sake of simplicity,
13-
// only the methods that satisfy the minimum required Runner interface are implemented.
14-
// Specifically, there are restrictions on evaluation, annotation comments, module inspection, and so on.
11+
// Runner is a mock that satisfies the Runner interface for plugin testing.
1512
type Runner struct {
1613
Files map[string]*hcl.File
1714
Issues Issues
1815
}
1916

20-
// WalkResourceAttributes searches for resources and passes the appropriate attributes to the walker function
17+
// WalkResourceAttributes visits all specified attributes from Files.
2118
func (r *Runner) WalkResourceAttributes(resourceType, attributeName string, walker func(*hcl.Attribute) error) error {
2219
for _, file := range r.Files {
2320
resources, _, diags := file.Body.PartialContent(&hcl.BodySchema{
@@ -60,7 +57,7 @@ func (r *Runner) WalkResourceAttributes(resourceType, attributeName string, walk
6057
return nil
6158
}
6259

63-
// WalkResources searches for resources with a specific type and passes to the walker function
60+
// WalkResources visits all specified resources from Files.
6461
func (r *Runner) WalkResources(resourceType string, walker func(*terraform.Resource) error) error {
6562
for _, file := range r.Files {
6663
resources, _, diags := file.Body.PartialContent(&hcl.BodySchema{
@@ -105,7 +102,7 @@ func (r *Runner) EvaluateExpr(expr hcl.Expression, ret interface{}) error {
105102
return gocty.FromCtyValue(val, ret)
106103
}
107104

108-
// EmitIssue adds an issue into the self
105+
// EmitIssue adds an issue to the runner itself.
109106
func (r *Runner) EmitIssue(rule tflint.Rule, message string, location hcl.Range, meta tflint.Metadata) error {
110107
r.Issues = append(r.Issues, &Issue{
111108
Rule: rule,
@@ -115,7 +112,7 @@ func (r *Runner) EmitIssue(rule tflint.Rule, message string, location hcl.Range,
115112
return nil
116113
}
117114

118-
// EnsureNoError is a method that simply run a function if there is no error
115+
// EnsureNoError is a method that simply runs a function if there is no error.
119116
func (r *Runner) EnsureNoError(err error, proc func() error) error {
120117
if err == nil {
121118
return proc()

helper/testing.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import (
1111
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
1212
)
1313

14-
// TestRunner returns a pseudo Runner for testing
14+
// TestRunner returns a mock Runner for testing.
15+
// You can pass the map of file names and their contents in the second argument.
1516
func TestRunner(t *testing.T, files map[string]string) *Runner {
1617
runner := &Runner{Files: map[string]*hcl.File{}, Issues: Issues{}}
1718
parser := hclparse.NewParser()
@@ -27,7 +28,7 @@ func TestRunner(t *testing.T, files map[string]string) *Runner {
2728
return runner
2829
}
2930

30-
// AssertIssues is an assertion helper for comparing issues
31+
// AssertIssues is an assertion helper for comparing issues.
3132
func AssertIssues(t *testing.T, expected Issues, actual Issues) {
3233
opts := []cmp.Option{
3334
// Byte field will be ignored because it's not important in tests such as positions
@@ -39,7 +40,7 @@ func AssertIssues(t *testing.T, expected Issues, actual Issues) {
3940
}
4041
}
4142

42-
// AssertIssuesWithoutRange is an assertion helper for comparing issues
43+
// AssertIssuesWithoutRange is an assertion helper for comparing issues except for range.
4344
func AssertIssuesWithoutRange(t *testing.T, expected Issues, actual Issues) {
4445
opts := []cmp.Option{
4546
cmpopts.IgnoreFields(Issue{}, "Range"),

plugin/client.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,21 @@ import (
88
"github.com/hashicorp/go-hclog"
99
plugin "github.com/hashicorp/go-plugin"
1010
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
11+
tfserver "github.com/terraform-linters/tflint-plugin-sdk/tflint/server"
1112
)
1213

13-
// Client is an RPC client for use by the host
14+
// Client is an RPC client for the host.
1415
type Client struct {
1516
rpcClient *rpc.Client
1617
broker *plugin.MuxBroker
1718
}
1819

19-
// ClientOpts is an option for initializing the RPC client
20+
// ClientOpts is an option for initializing a Client.
2021
type ClientOpts struct {
2122
Cmd *exec.Cmd
2223
}
2324

24-
// NewClient is a wrapper of plugin.NewClient
25+
// NewClient is a wrapper of plugin.NewClient.
2526
func NewClient(opts *ClientOpts) *plugin.Client {
2627
return plugin.NewClient(&plugin.ClientConfig{
2728
HandshakeConfig: handshakeConfig,
@@ -37,35 +38,37 @@ func NewClient(opts *ClientOpts) *plugin.Client {
3738
})
3839
}
3940

40-
// RuleSetName queries the RPC server for RuleSetName
41+
// RuleSetName calls the server-side RuleSetName method and returns its name.
4142
func (c *Client) RuleSetName() (string, error) {
4243
var resp string
4344
err := c.rpcClient.Call("Plugin.RuleSetName", new(interface{}), &resp)
4445
return resp, err
4546
}
4647

47-
// RuleSetVersion queries the RPC server for RuleSetVersion
48+
// RuleSetVersion calls the server-side RuleSetVersion method and returns its version.
4849
func (c *Client) RuleSetVersion() (string, error) {
4950
var resp string
5051
err := c.rpcClient.Call("Plugin.RuleSetVersion", new(interface{}), &resp)
5152
return resp, err
5253
}
5354

54-
// RuleNames queries the RPC server for RuleNames
55+
// RuleNames calls the server-side RuleNames method and returns the list of names.
5556
func (c *Client) RuleNames() ([]string, error) {
5657
var resp []string
5758
err := c.rpcClient.Call("Plugin.RuleNames", new(interface{}), &resp)
5859
return resp, err
5960
}
6061

61-
// ApplyConfig queries the RPC server for ApplyConfig
62+
// ApplyConfig calls the server-side ApplyConfig method.
6263
func (c *Client) ApplyConfig(config *tflint.Config) error {
6364
return c.rpcClient.Call("Plugin.ApplyConfig", config, new(interface{}))
6465
}
6566

66-
// Check queries the RPC server for Check
67-
// For bi-directional communication, you can pass a server that accepts Runner's queries
68-
func (c *Client) Check(server tflint.Server) error {
67+
// Check calls the server-side Check method.
68+
// At the same time, it starts the server to respond to requests from the plugin side.
69+
// Note that this server (tfserver.Server) serves clients that satisfy the Runner interface
70+
// and is different from the server (plugin.Server) that provides the plugin system.
71+
func (c *Client) Check(server tfserver.Server) error {
6972
brokerID := c.broker.NextId()
7073
go c.broker.AcceptAndServe(brokerID, server)
7174

plugin/doc.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Package plugin contains the implementations needed to make
2+
// the built binary act as a plugin.
3+
//
4+
// A plugin is implemented as an RPC server and the host acts
5+
// as the client, sending analysis requests to the plugin.
6+
// Note that the server-client relationship here is the opposite of
7+
// the communication that takes place during the checking phase.
8+
//
9+
// Implementation details are hidden in go-plugin. This package is
10+
// essentially a wrapper for go-plugin.
11+
package plugin

plugin/plugin.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,28 @@ import (
88
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
99
)
1010

11-
// handShakeConfig is used for UX. ProcotolVersion will be updated by incompatible changes
11+
// handShakeConfig is used for UX. ProcotolVersion will be updated by incompatible changes.
1212
var handshakeConfig = plugin.HandshakeConfig{
1313
ProtocolVersion: 1,
1414
MagicCookieKey: "TFLINT_RULESET_PLUGIN",
1515
MagicCookieValue: "5adSn1bX8nrDfgBqiAqqEkC6OE1h3iD8SqbMc5UUONx8x3xCF0KlPDsBRNDjoYDP",
1616
}
1717

18-
// RuleSetPlugin is a wrapper to satisfy the interface of go-plugin
18+
// RuleSetPlugin is a wrapper to satisfy the interface of go-plugin.
1919
type RuleSetPlugin struct {
2020
impl tflint.RuleSet
2121
}
2222

23-
// Server returns an RPC server acting as a plugin
23+
// Server returns an RPC server acting as a plugin.
2424
func (p *RuleSetPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
2525
return &Server{impl: p.impl, broker: b}, nil
2626
}
2727

28-
// Client returns an RPC client for use by the host
28+
// Client returns an RPC client for the host.
2929
func (RuleSetPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
3030
return &Client{rpcClient: c, broker: b}, nil
3131
}
3232

33-
// In order to communicate the interface correctly with RPC,
34-
// the type of the related structure is registered in gob at the initial time.
3533
func init() {
3634
gob.Register(tflint.Error{})
3735
}

plugin/server.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,22 @@ package plugin
33
import (
44
plugin "github.com/hashicorp/go-plugin"
55
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
6+
tfclient "github.com/terraform-linters/tflint-plugin-sdk/tflint/client"
67
)
78

8-
// Server is an RPC server acting as a plugin
9+
// Server is an RPC server acting as a plugin.
910
type Server struct {
1011
impl tflint.RuleSet
1112
broker *plugin.MuxBroker
1213
}
1314

14-
// ServeOpts is an option for serving a plugin
15-
// Each plugin can pass a RuleSet that represents its own functionality
15+
// ServeOpts is an option for serving a plugin.
16+
// Each plugin can pass a RuleSet that represents its own functionality.
1617
type ServeOpts struct {
1718
RuleSet tflint.RuleSet
1819
}
1920

20-
// Serve is a wrapper of plugin.Serve. This is entrypoint of all plugins
21+
// Serve is a wrapper of plugin.Serve. This is entrypoint of all plugins.
2122
func Serve(opts *ServeOpts) {
2223
plugin.Serve(&plugin.ServeConfig{
2324
HandshakeConfig: handshakeConfig,
@@ -27,36 +28,37 @@ func Serve(opts *ServeOpts) {
2728
})
2829
}
2930

30-
// RuleSetName replies its own the result of RuleSetName
31+
// RuleSetName returns the name of the plugin.
3132
func (s *Server) RuleSetName(args interface{}, resp *string) error {
3233
*resp = s.impl.RuleSetName()
3334
return nil
3435
}
3536

36-
// RuleSetVersion replies its own the result of RuleSetVersion
37+
// RuleSetVersion returns the version of the plugin.
3738
func (s *Server) RuleSetVersion(args interface{}, resp *string) error {
3839
*resp = s.impl.RuleSetVersion()
3940
return nil
4041
}
4142

42-
// RuleNames replies its own the result of RuleNames
43+
// RuleNames returns the list of rule names provided by the plugin.
4344
func (s *Server) RuleNames(args interface{}, resp *[]string) error {
4445
*resp = s.impl.RuleNames()
4546
return nil
4647
}
4748

48-
// ApplyConfig applies the passed config to its own plugin implementation
49+
// ApplyConfig applies the passed config to its own plugin implementation.
4950
func (s *Server) ApplyConfig(config *tflint.Config, resp *interface{}) error {
5051
s.impl.ApplyConfig(config)
5152
return nil
5253
}
5354

54-
// Check initializes an RPC client that can query to the host process and pass it to the Check method
55+
// Check calls its own plugin implementation with an RPC client that can send
56+
// requests to the host process.
5557
func (s *Server) Check(brokerID uint32, resp *interface{}) error {
5658
conn, err := s.broker.Dial(brokerID)
5759
if err != nil {
5860
return err
5961
}
6062

61-
return s.impl.Check(tflint.NewClient(conn))
63+
return s.impl.Check(tfclient.NewClient(conn))
6264
}

0 commit comments

Comments
 (0)