Skip to content

Commit 3c3ab13

Browse files
Miouge1bendrucker
andauthored
new rule: deprecated_lookup (#128)
Co-authored-by: Ben Drucker <[email protected]>
1 parent eedaa2b commit 3c3ab13

File tree

5 files changed

+251
-0
lines changed

5 files changed

+251
-0
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ All rules are enabled by default, but by setting `preset = "recommended"`, you c
99
|[terraform_comment_syntax](terraform_comment_syntax.md)|Disallow `//` comments in favor of `#`||
1010
|[terraform_deprecated_index](terraform_deprecated_index.md)|Disallow legacy dot index syntax||
1111
|[terraform_deprecated_interpolation](terraform_deprecated_interpolation.md)|Disallow deprecated (0.11-style) interpolation||
12+
|[terraform_deprecated_lookup](terraform_deprecated_lookup.md)|Disallow deprecated `lookup()` function with only 2 arguments.||
1213
|[terraform_documented_outputs](terraform_documented_outputs.md)|Disallow `output` declarations without description||
1314
|[terraform_documented_variables](terraform_documented_variables.md)|Disallow `variable` declarations without description||
1415
|[terraform_empty_list_equality](terraform_empty_list_equality.md)|Disallow comparisons with `[]` when checking if a collection is empty||
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# terraform_deprecated_lookup
2+
3+
Disallow deprecated [`lookup` function](https://developer.hashicorp.com/terraform/language/functions/lookup) usage without a default.
4+
5+
## Example
6+
7+
```hcl
8+
locals {
9+
map = { a = 0 }
10+
value = lookup(local.map, "a")
11+
}
12+
```
13+
14+
```
15+
$ tflint
16+
1 issue(s) found:
17+
18+
Warning: [Fixable] Lookup with 2 arguments is deprecated (terraform_deprecated_lookup)
19+
20+
on main.tf line 3:
21+
3: value = lookup(local.map, "a")
22+
23+
Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_deprecated_lookup.md
24+
```
25+
26+
## Why
27+
28+
Calling [`lookup`](https://developer.hashicorp.com/terraform/language/functions/lookup) with 2 arguments has been deprecated since Terraform v0.7. `lookup(map, key)` is equivalent to the native index syntax `map[key]`. `lookup` should only be used with the third `default` argument, even though it is optional for backward compatiblity.
29+
30+
## How To Fix
31+
32+
Use the native index syntax:
33+
34+
Example:
35+
36+
```hcl
37+
locals {
38+
map = { a = 0 }
39+
value = lookup(local.map, "a")
40+
}
41+
```
42+
43+
Change this to:
44+
45+
```hcl
46+
locals {
47+
map = { a = 0 }
48+
value = local.map["a"]
49+
}
50+
```

rules/preset.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var PresetRules = map[string][]tflint.Rule{
2020
NewTerraformUnusedDeclarationsRule(),
2121
NewTerraformUnusedRequiredProvidersRule(),
2222
NewTerraformWorkspaceRemoteRule(),
23+
NewTerraformDeprecatedLookupRule(),
2324
},
2425
"recommended": {
2526
NewTerraformDeprecatedIndexRule(),
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package rules
2+
3+
import (
4+
"github.com/hashicorp/hcl/v2"
5+
"github.com/hashicorp/hcl/v2/hclsyntax"
6+
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
7+
"github.com/terraform-linters/tflint-ruleset-terraform/project"
8+
)
9+
10+
// TerraformDeprecatedLookupRule warns about usage of the legacy dot syntax for indexes (foo.0)
11+
type TerraformDeprecatedLookupRule struct {
12+
tflint.DefaultRule
13+
}
14+
15+
// NewTerraformDeprecatedIndexRule return a new rule
16+
func NewTerraformDeprecatedLookupRule() *TerraformDeprecatedLookupRule {
17+
return &TerraformDeprecatedLookupRule{}
18+
}
19+
20+
// Name returns the rule name
21+
func (r *TerraformDeprecatedLookupRule) Name() string {
22+
return "terraform_deprecated_lookup"
23+
}
24+
25+
// Enabled returns whether the rule is enabled by default
26+
func (r *TerraformDeprecatedLookupRule) Enabled() bool {
27+
return true
28+
}
29+
30+
// Severity returns the rule severity
31+
func (r *TerraformDeprecatedLookupRule) Severity() tflint.Severity {
32+
return tflint.WARNING
33+
}
34+
35+
// Link returns the rule reference link
36+
func (r *TerraformDeprecatedLookupRule) Link() string {
37+
return project.ReferenceLink(r.Name())
38+
}
39+
40+
// Check walks all expressions and emit issues if deprecated index syntax is found
41+
func (r *TerraformDeprecatedLookupRule) Check(runner tflint.Runner) error {
42+
path, err := runner.GetModulePath()
43+
if err != nil {
44+
return err
45+
}
46+
if !path.IsRoot() {
47+
// This rule does not evaluate child modules.
48+
return nil
49+
}
50+
51+
diags := runner.WalkExpressions(tflint.ExprWalkFunc(func(e hcl.Expression) hcl.Diagnostics {
52+
call, ok := e.(*hclsyntax.FunctionCallExpr)
53+
if ok && call.Name == "lookup" && len(call.Args) == 2 {
54+
if err := runner.EmitIssueWithFix(
55+
r,
56+
"Lookup with 2 arguments is deprecated",
57+
call.Range(),
58+
func(f tflint.Fixer) error {
59+
return f.ReplaceText(call.Range(), f.TextAt(call.Args[0].Range()), "[", f.TextAt(call.Args[1].Range()), "]")
60+
},
61+
); err != nil {
62+
return hcl.Diagnostics{
63+
{
64+
Severity: hcl.DiagError,
65+
Summary: "failed to call EmitIssueWithFix()",
66+
Detail: err.Error(),
67+
},
68+
}
69+
}
70+
return nil
71+
}
72+
return nil
73+
}))
74+
if diags.HasErrors() {
75+
return diags
76+
}
77+
78+
return nil
79+
}
80+
81+
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package rules
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/hcl/v2"
7+
"github.com/terraform-linters/tflint-plugin-sdk/helper"
8+
)
9+
10+
func Test_TerraformDeprecatedLookupRule(t *testing.T) {
11+
cases := []struct {
12+
Name string
13+
Content string
14+
Expected helper.Issues
15+
Fixed string
16+
}{
17+
{
18+
Name: "deprecated lookup",
19+
Content: `
20+
locals {
21+
map = { a = 0 }
22+
value = lookup(local.map, "a")
23+
}
24+
`,
25+
Expected: helper.Issues{
26+
{
27+
Rule: NewTerraformDeprecatedLookupRule(),
28+
Message: "Lookup with 2 arguments is deprecated",
29+
Range: hcl.Range{
30+
Filename: "config.tf",
31+
Start: hcl.Pos{
32+
Line: 4,
33+
Column: 11,
34+
},
35+
End: hcl.Pos{
36+
Line: 4,
37+
Column: 33,
38+
},
39+
},
40+
},
41+
},
42+
Fixed: `
43+
locals {
44+
map = { a = 0 }
45+
value = local.map["a"]
46+
}
47+
`,
48+
},
49+
{
50+
Name: "deprecated lookup nested",
51+
Content: `
52+
locals {
53+
map = { a = { b = 0 } }
54+
value = lookup(lookup(local.map, "a"), "b")
55+
}
56+
`,
57+
Expected: helper.Issues{
58+
{
59+
Rule: NewTerraformDeprecatedLookupRule(),
60+
Message: "Lookup with 2 arguments is deprecated",
61+
Range: hcl.Range{
62+
Filename: "config.tf",
63+
Start: hcl.Pos{
64+
Line: 4,
65+
Column: 11,
66+
},
67+
End: hcl.Pos{
68+
Line: 4,
69+
Column: 46,
70+
},
71+
},
72+
},
73+
{
74+
Rule: NewTerraformDeprecatedLookupRule(),
75+
Message: "Lookup with 2 arguments is deprecated",
76+
Range: hcl.Range{
77+
Filename: "config.tf",
78+
Start: hcl.Pos{
79+
Line: 4,
80+
Column: 18,
81+
},
82+
End: hcl.Pos{
83+
Line: 4,
84+
Column: 40,
85+
},
86+
},
87+
},
88+
},
89+
Fixed: `
90+
locals {
91+
map = { a = { b = 0 } }
92+
value = local.map["a"]["b"]
93+
}
94+
`,
95+
},
96+
}
97+
98+
rule := NewTerraformDeprecatedLookupRule()
99+
100+
for _, tc := range cases {
101+
t.Run(tc.Name, func(t *testing.T) {
102+
filename := "config.tf"
103+
104+
runner := helper.TestRunner(t, map[string]string{filename: tc.Content})
105+
106+
if err := rule.Check(runner); err != nil {
107+
t.Fatalf("Unexpected error occurred: %s", err)
108+
}
109+
110+
helper.AssertIssues(t, tc.Expected, runner.Issues)
111+
want := map[string]string{}
112+
if tc.Fixed != "" {
113+
want[filename] = tc.Fixed
114+
}
115+
helper.AssertChanges(t, want, runner.Changes())
116+
})
117+
}
118+
}

0 commit comments

Comments
 (0)