Skip to content

Commit 5eeb34e

Browse files
authored
Return a file from other modules (#1469)
1 parent 8390b67 commit 5eeb34e

File tree

15 files changed

+181
-12
lines changed

15 files changed

+181
-12
lines changed

cmd/inspect.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func (cli *CLI) inspect(opts Options, dir string, filterFiles []string) int {
9898

9999
for _, ruleset := range rulesetPlugin.RuleSets {
100100
for _, runner := range runners {
101-
err = ruleset.Check(plugin.NewGRPCServer(runner, rootRunner, cli.loader.Sources()))
101+
err = ruleset.Check(plugin.NewGRPCServer(runner, rootRunner, cli.loader.Files()))
102102
if err != nil {
103103
cli.formatter.Print(tflint.Issues{}, fmt.Errorf("Failed to check ruleset; %w", err), cli.loader.Sources())
104104
return ExitCodeError
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"Modules":[{"Key":"route53_records","Source":"./module","Dir":"module"},{"Key":"","Source":"","Dir":"."}]}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
plugin "testing" {
2+
enabled = true
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
resource "aws_route53_record" "www" {
2+
zone_id = aws_route53_zone.primary.zone_id
3+
name = "www.example.com"
4+
type = "A"
5+
ttl = 300
6+
records = [aws_eip.lb.public_ip]
7+
}
8+
9+
module "route53_records" {
10+
source = "./module"
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
resource "aws_route53_record" "help" {
2+
zone_id = aws_route53_zone.primary.zone_id
3+
name = "help.example.com"
4+
type = "A"
5+
ttl = 300
6+
records = [aws_eip.lb.public_ip]
7+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"issues": [
3+
{
4+
"rule": {
5+
"name": "aws_route53_record_eval_on_root_ctx_example",
6+
"severity": "error",
7+
"link": ""
8+
},
9+
"message": "record name (root): \"www.example.com\"",
10+
"range": {
11+
"filename": "module.tf",
12+
"start": {
13+
"line": 3,
14+
"column": 13
15+
},
16+
"end": {
17+
"line": 3,
18+
"column": 30
19+
}
20+
},
21+
"callers": []
22+
}
23+
],
24+
"errors": []
25+
}

integrationtest/inspection/inspection_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ func TestIntegration(t *testing.T) {
152152
Command: "tflint --enable-plugin testing --format json",
153153
Dir: "enable-plugin-by-cli",
154154
},
155+
{
156+
Name: "eval on root context",
157+
Command: "tflint --module --format json",
158+
Dir: "eval-on-root-context",
159+
},
155160
}
156161

157162
dir, _ := os.Getwd()

langserver/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ func (h *handler) inspect() (map[string][]lsp.Diagnostic, error) {
196196
return ret, fmt.Errorf("Failed to apply config to `%s` plugin", name)
197197
}
198198
for _, runner := range runners {
199-
err = ruleset.Check(plugin.NewGRPCServer(runner, runners[len(runners)-1], loader.Sources()))
199+
err = ruleset.Check(plugin.NewGRPCServer(runner, runners[len(runners)-1], loader.Files()))
200200
if err != nil {
201201
return ret, fmt.Errorf("Failed to check ruleset: %w", err)
202202
}

plugin/server.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import (
1515
type GRPCServer struct {
1616
runner *tflint.Runner
1717
rootRunner *tflint.Runner
18-
sources map[string][]byte
18+
files map[string]*hcl.File
1919
}
2020

2121
// NewGRPCServer initializes a gRPC server for plugins.
22-
func NewGRPCServer(runner *tflint.Runner, rootRunner *tflint.Runner, sources map[string][]byte) *GRPCServer {
23-
return &GRPCServer{runner: runner, rootRunner: rootRunner, sources: sources}
22+
func NewGRPCServer(runner *tflint.Runner, rootRunner *tflint.Runner, files map[string]*hcl.File) *GRPCServer {
23+
return &GRPCServer{runner: runner, rootRunner: rootRunner, files: files}
2424
}
2525

2626
// GetModuleContent returns module content based on the passed schema and options.
@@ -37,7 +37,7 @@ func (s *GRPCServer) GetModuleContent(bodyS *hclext.BodySchema, opts sdk.GetModu
3737

3838
// GetFile returns the hcl.File based on passed the file name.
3939
func (s *GRPCServer) GetFile(name string) (*hcl.File, error) {
40-
return s.runner.File(name), nil
40+
return s.files[name], nil
4141
}
4242

4343
// GetFiles returns all hcl.File in the module.

plugin/server_test.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ resource "aws_instance" "bar" {
2626
instance_type = "m5.2xlarge"
2727
}`})
2828

29-
server := NewGRPCServer(runner, rootRunner, map[string][]byte{})
29+
server := NewGRPCServer(runner, rootRunner, runner.Files())
3030

3131
tests := []struct {
3232
Name string
@@ -128,8 +128,18 @@ resource "aws_instance" "bar" {
128128
instance_type = "m5.2xlarge"
129129
}`,
130130
})
131+
rootRunner := tflint.TestRunner(t, map[string]string{
132+
"test_on_root1.tf": `
133+
resource "aws_instance" "foo" {
134+
instance_type = "t2.nano"
135+
}`,
136+
})
137+
files := runner.Files()
138+
for name, file := range rootRunner.Files() {
139+
files[name] = file
140+
}
131141

132-
server := NewGRPCServer(runner, nil, map[string][]byte{})
142+
server := NewGRPCServer(runner, rootRunner, files)
133143

134144
tests := []struct {
135145
Name string
@@ -157,6 +167,14 @@ resource "aws_instance" "bar" {
157167
Arg: "test3.tf",
158168
Want: "",
159169
},
170+
{
171+
Name: "get file from root module",
172+
Arg: "test_on_root1.tf",
173+
Want: `
174+
resource "aws_instance" "foo" {
175+
instance_type = "t2.nano"
176+
}`,
177+
},
160178
}
161179

162180
for _, test := range tests {
@@ -188,7 +206,7 @@ resource "aws_instance" "bar" {
188206
instance_type = "m5.2xlarge"
189207
}`})
190208

191-
server := NewGRPCServer(runner, rootRunner, map[string][]byte{})
209+
server := NewGRPCServer(runner, rootRunner, runner.Files())
192210

193211
tests := []struct {
194212
Name string
@@ -252,7 +270,7 @@ rule "test_in_file" {
252270
fileConfig.Merge(cliConfig)
253271
runner := tflint.TestRunnerWithConfig(t, map[string]string{}, fileConfig)
254272

255-
server := NewGRPCServer(runner, nil, map[string][]byte{})
273+
server := NewGRPCServer(runner, nil, runner.Files())
256274

257275
// default error check helper
258276
neverHappend := func(err error) bool { return err != nil }
@@ -335,7 +353,7 @@ variable "foo" {
335353
default = "baz"
336354
}`})
337355

338-
server := NewGRPCServer(runner, rootRunner, map[string][]byte{})
356+
server := NewGRPCServer(runner, rootRunner, runner.Files())
339357

340358
// test util functions
341359
hclExpr := func(expr string) hcl.Expression {
@@ -451,7 +469,7 @@ resource "aws_instance" "foo" {
451469
t.Run(test.Name, func(t *testing.T) {
452470
runner := tflint.TestRunner(t, map[string]string{"main.tf": config})
453471

454-
server := NewGRPCServer(runner, nil, map[string][]byte{})
472+
server := NewGRPCServer(runner, nil, runner.Files())
455473

456474
err := server.EmitIssue(test.Args())
457475
if err != nil {

plugin/stub-generator/sources/testing/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func main() {
1818
rules.NewAwsS3BucketExampleLifecycleRuleRule(),
1919
rules.NewAwsInstanceMapEvalExampleRule(),
2020
rules.NewAwsS3BucketWithConfigExampleRule(),
21+
rules.NewAwsRoute53RecordEvalOnRootCtxExampleRule(),
2122
},
2223
},
2324
})
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package rules
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
7+
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
8+
)
9+
10+
// AwsRoute53RecordEvalOnRootCtxExampleRule checks whether ...
11+
type AwsRoute53RecordEvalOnRootCtxExampleRule struct {
12+
tflint.DefaultRule
13+
}
14+
15+
// NewAwsRoute53RecordEvalOnRootCtxExampleRule returns a new rule
16+
func NewAwsRoute53RecordEvalOnRootCtxExampleRule() *AwsRoute53RecordEvalOnRootCtxExampleRule {
17+
return &AwsRoute53RecordEvalOnRootCtxExampleRule{}
18+
}
19+
20+
// Name returns the rule name
21+
func (r *AwsRoute53RecordEvalOnRootCtxExampleRule) Name() string {
22+
return "aws_route53_record_eval_on_root_ctx_example"
23+
}
24+
25+
// Enabled returns whether the rule is enabled by default
26+
func (r *AwsRoute53RecordEvalOnRootCtxExampleRule) Enabled() bool {
27+
return true
28+
}
29+
30+
// Severity returns the rule severity
31+
func (r *AwsRoute53RecordEvalOnRootCtxExampleRule) Severity() tflint.Severity {
32+
return tflint.ERROR
33+
}
34+
35+
// Link returns the rule reference link
36+
func (r *AwsRoute53RecordEvalOnRootCtxExampleRule) Link() string {
37+
return ""
38+
}
39+
40+
// Check checks whether ...
41+
func (r *AwsRoute53RecordEvalOnRootCtxExampleRule) Check(runner tflint.Runner) error {
42+
resources, err := runner.GetResourceContent("aws_route53_record", &hclext.BodySchema{
43+
Attributes: []hclext.AttributeSchema{{Name: "name"}},
44+
}, &tflint.GetModuleContentOption{ModuleCtx: tflint.RootModuleCtxType})
45+
if err != nil {
46+
return err
47+
}
48+
49+
for _, resource := range resources.Blocks {
50+
attribute, exists := resource.Body.Attributes["name"]
51+
if !exists {
52+
continue
53+
}
54+
55+
var name string
56+
err := runner.EvaluateExpr(attribute.Expr, &name, &tflint.EvaluateExprOption{ModuleCtx: tflint.RootModuleCtxType})
57+
58+
err = runner.EnsureNoError(err, func() error {
59+
return runner.EmitIssue(
60+
r,
61+
fmt.Sprintf("record name (root): %#v", name),
62+
attribute.Expr.Range(),
63+
)
64+
})
65+
if err != nil {
66+
return err
67+
}
68+
}
69+
70+
return nil
71+
}

terraform/parser.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ func (p *Parser) Sources() map[string][]byte {
160160
return p.p.Sources()
161161
}
162162

163+
// Files returns a map of the cached HCL file objects for all files that
164+
// have been loaded through this parser, with source filenames (as requested
165+
// when each file was opened) as the keys.
166+
func (p *Parser) Files() map[string]*hcl.File {
167+
return p.p.Files()
168+
}
169+
163170
// ConfigDirFiles returns lists of the primary and override files configuration
164171
// files in the given directory.
165172
//

tflint/loader.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type AbstractLoader interface {
2525
LoadAnnotations(string) (map[string]Annotations, error)
2626
LoadValuesFiles(...string) ([]terraform.InputValues, error)
2727
Sources() map[string][]byte
28+
Files() map[string]*hcl.File
2829
}
2930

3031
// Loader is a wrapper of Terraform's configload.Loader
@@ -169,6 +170,10 @@ func (l *Loader) Sources() map[string][]byte {
169170
return l.tfparser.Sources()
170171
}
171172

173+
func (l *Loader) Files() map[string]*hcl.File {
174+
return l.tfparser.Files()
175+
}
176+
172177
// autoLoadValuesFiles returns all files which match *.auto.tfvars present in the current directory
173178
// The list is sorted alphabetically. This is equivalent to priority
174179
// Please note that terraform.tfvars is not included in this list

tflint/loader_mock.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)