Skip to content
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

Add autofix support #93

Merged
merged 1 commit into from
Jun 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/hcl/v2 v2.16.2
github.com/hashicorp/terraform-registry-address v0.2.0
github.com/terraform-linters/tflint-plugin-sdk v0.16.1
github.com/terraform-linters/tflint-plugin-sdk v0.16.2-0.20230605170513-64de942491dc
github.com/zclconf/go-cty v1.13.2
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/terraform-linters/tflint-plugin-sdk v0.16.1 h1:fBfLL8KzP3pkQrNp3iQxaGoKBoMo2sFYoqmhuo6yc+A=
github.com/terraform-linters/tflint-plugin-sdk v0.16.1/go.mod h1:ltxVy04PRwptL6P/Ugz2ZeTNclYapClrLn/kVFXJGzo=
github.com/terraform-linters/tflint-plugin-sdk v0.16.2-0.20230605170513-64de942491dc h1:z0PQWOWfWOYps2Oo7nT/v9XASazFZITnMA+oGWZzB78=
github.com/terraform-linters/tflint-plugin-sdk v0.16.2-0.20230605170513-64de942491dc/go.mod h1:ltxVy04PRwptL6P/Ugz2ZeTNclYapClrLn/kVFXJGzo=
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
Expand Down
5 changes: 4 additions & 1 deletion rules/terraform_comment_syntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,13 @@ func (r *TerraformCommentSyntaxRule) checkComments(runner tflint.Runner, filenam
}

if strings.HasPrefix(string(token.Bytes), "//") {
if err := runner.EmitIssue(
if err := runner.EmitIssueWithFix(
r,
"Single line comments should begin with #",
token.Range,
func(f tflint.Fixer) error {
return f.ReplaceText(f.RangeTo("//", filename, token.Range.Start), "#")
},
); err != nil {
return err
}
Expand Down
7 changes: 7 additions & 0 deletions rules/terraform_comment_syntax_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func Test_TerraformCommentSyntaxRule(t *testing.T) {
Content string
JSON bool
Expected helper.Issues
Fixed string
}{
{
Name: "hash comment",
Expand Down Expand Up @@ -48,6 +49,7 @@ func Test_TerraformCommentSyntaxRule(t *testing.T) {
},
},
},
Fixed: `# foo`,
},
{
Name: "end-of-line hash comment",
Expand Down Expand Up @@ -82,6 +84,11 @@ variable "foo" {
}

helper.AssertIssues(t, tc.Expected, runner.Issues)
want := map[string]string{}
if tc.Fixed != "" {
want[filename] = tc.Fixed
}
helper.AssertChanges(t, want, runner.Changes())
})
}
}
16 changes: 11 additions & 5 deletions rules/terraform_deprecated_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,18 @@ func (r *TerraformDeprecatedIndexRule) Check(runner tflint.Runner) error {
r.checkLegacyTraversalIndex(runner, expr.Traversal, file.Bytes)
case *hclsyntax.SplatExpr:
if strings.HasPrefix(string(expr.MarkerRange.SliceBytes(file.Bytes)), ".") {
if err := runner.EmitIssue(
if err := runner.EmitIssueWithFix(
r,
"List items should be accessed using square brackets",
expr.MarkerRange,
func(f tflint.Fixer) error {
return f.ReplaceText(expr.MarkerRange, "[*]")
},
); err != nil {
return hcl.Diagnostics{
{
Severity: hcl.DiagError,
Summary: "failed to call EmitIssue()",
Summary: "failed to call EmitIssueWithFix()",
Detail: err.Error(),
},
}
Expand All @@ -98,17 +101,20 @@ func (r *TerraformDeprecatedIndexRule) Check(runner tflint.Runner) error {

func (r *TerraformDeprecatedIndexRule) checkLegacyTraversalIndex(runner tflint.Runner, traversal hcl.Traversal, file []byte) hcl.Diagnostics {
for _, t := range traversal {
if _, ok := t.(hcl.TraverseIndex); ok {
if tn, ok := t.(hcl.TraverseIndex); ok {
if strings.HasPrefix(string(t.SourceRange().SliceBytes(file)), ".") {
if err := runner.EmitIssue(
if err := runner.EmitIssueWithFix(
r,
"List items should be accessed using square brackets",
t.SourceRange(),
func(f tflint.Fixer) error {
return f.ReplaceText(t.SourceRange(), "[", f.ValueText(tn.Key), "]")
},
); err != nil {
return hcl.Diagnostics{
{
Severity: hcl.DiagError,
Summary: "failed to call EmitIssue()",
Summary: "failed to call EmitIssueWithFix()",
Detail: err.Error(),
},
}
Expand Down
94 changes: 70 additions & 24 deletions rules/terraform_deprecated_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ func Test_TerraformDeprecatedIndexRule(t *testing.T) {
Content string
JSON bool
Expected helper.Issues
Fixed string
}{
{
Name: "deprecated dot index style",
Content: `
locals {
list = ["a"]
list = ["a"]
value = list.0
}
`,
Expand All @@ -39,13 +40,19 @@ locals {
},
},
},
Fixed: `
locals {
list = ["a"]
value = list[0]
}
`,
},
{
Name: "deprecated dot splat index style",
Content: `
locals {
maplist = [{a = "b"}]
values = maplist.*.a
maplist = [{ a = "b" }]
values = maplist.*.a
}
`,
Expected: helper.Issues{
Expand All @@ -56,21 +63,27 @@ locals {
Filename: "config.tf",
Start: hcl.Pos{
Line: 4,
Column: 19,
Column: 20,
},
End: hcl.Pos{
Line: 4,
Column: 21,
Column: 22,
},
},
},
},
Fixed: `
locals {
maplist = [{ a = "b" }]
values = maplist[*].a
}
`,
},
{
Name: "attribute access",
Content: `
locals {
map = {a = "b"}
map = { a = "b" }
value = map.a
}
`,
Expand All @@ -90,9 +103,9 @@ locals {
Content: `
locals {
servers = <<EOF
%{ for ip in aws_instance.example[*].private_ip }
%{for ip in aws_instance.example[*].private_ip}
server ${ip}
%{ endfor }
%{endfor}
EOF
}
`,
Expand All @@ -101,14 +114,14 @@ EOF
{
Name: "directive: invalid",
Content: `
locals {
servers = <<EOF
%{ for ip in aws_instance.example.*.private_ip }
server ${ip}
%{ endfor }
EOF
}
`,
locals {
servers = <<EOF
%{for ip in aws_instance.example.*.private_ip}
server ${ip}
%{endfor}
EOF
}
`,
Expected: helper.Issues{
{
Rule: NewTerraformDeprecatedIndexRule(),
Expand All @@ -117,22 +130,31 @@ EOF
Filename: "config.tf",
Start: hcl.Pos{
Line: 4,
Column: 36,
Column: 33,
},
End: hcl.Pos{
Line: 4,
Column: 38,
Column: 35,
},
},
},
},
Fixed: `
locals {
servers = <<EOF
%{for ip in aws_instance.example[*].private_ip}
server ${ip}
%{endfor}
EOF
}
`,
},
{
Name: "legacy splat and legacy index",
Content: `
locals {
nested_list = [["a"]]
value = nested_list.*.0
value = nested_list.*.0
}
`,
Expected: helper.Issues{
Expand All @@ -143,11 +165,11 @@ locals {
Filename: "config.tf",
Start: hcl.Pos{
Line: 4,
Column: 22,
Column: 28,
},
End: hcl.Pos{
Line: 4,
Column: 24,
Column: 30,
},
},
},
Expand All @@ -158,21 +180,27 @@ locals {
Filename: "config.tf",
Start: hcl.Pos{
Line: 4,
Column: 24,
Column: 30,
},
End: hcl.Pos{
Line: 4,
Column: 26,
Column: 32,
},
},
},
},
Fixed: `
locals {
nested_list = [["a"]]
value = nested_list[*][0]
}
`,
},
{
Name: "complex expression",
Content: `
locals {
create_namespace = true
create_namespace = true
kubernetes_namespace = local.create_namespace ? join("", kubernetes_namespace.default.*.id) : var.kubernetes_namespace
}
`,
Expand All @@ -193,6 +221,12 @@ locals {
},
},
},
Fixed: `
locals {
create_namespace = true
kubernetes_namespace = local.create_namespace ? join("", kubernetes_namespace.default[*].id) : var.kubernetes_namespace
}
`,
},
{
Name: "json invalid",
Expand Down Expand Up @@ -221,6 +255,13 @@ locals {
},
},
},
Fixed: `
{
"locals": {
"list": ["a"],
"value": "${list[0]}"
}
}`,
},
{
Name: "json valid",
Expand Down Expand Up @@ -264,6 +305,11 @@ locals {
}

helper.AssertIssues(t, tc.Expected, runner.Issues)
want := map[string]string{}
if tc.Fixed != "" {
want[filename] = tc.Fixed
}
helper.AssertChanges(t, want, runner.Changes())
})
}
}
10 changes: 7 additions & 3 deletions rules/terraform_deprecated_interpolation.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,24 @@ func (r *TerraformDeprecatedInterpolationRule) Check(runner tflint.Runner) error
}

func (r *TerraformDeprecatedInterpolationRule) checkForDeprecatedInterpolationsInExpr(runner tflint.Runner, expr hcl.Expression) hcl.Diagnostics {
if _, ok := expr.(*hclsyntax.TemplateWrapExpr); !ok {
wrapExpr, ok := expr.(*hclsyntax.TemplateWrapExpr)
if !ok {
return nil
}

err := runner.EmitIssue(
err := runner.EmitIssueWithFix(
r,
"Interpolation-only expressions are deprecated in Terraform v0.12.14",
expr.Range(),
func(f tflint.Fixer) error {
return f.ReplaceText(expr.Range(), f.TextAt(wrapExpr.Wrapped.Range()))
},
)
if err != nil {
return hcl.Diagnostics{
{
Severity: hcl.DiagError,
Summary: "failed to call EmitIssue()",
Summary: "failed to call EmitIssueWithFix()",
Detail: err.Error(),
},
}
Expand Down
Loading