Skip to content

Commit

Permalink
Add terraform.Runner (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
wata727 authored Aug 27, 2022
1 parent 88cbcf6 commit 11c44ac
Show file tree
Hide file tree
Showing 19 changed files with 749 additions and 403 deletions.
12 changes: 12 additions & 0 deletions rules/rules_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package rules

import (
"testing"

"github.com/terraform-linters/tflint-plugin-sdk/helper"
"github.com/terraform-linters/tflint-ruleset-terraform/terraform"
)

func testRunner(t *testing.T, files map[string]string) *terraform.Runner {
return terraform.NewRunner(helper.TestRunner(t, files))
}
42 changes: 20 additions & 22 deletions rules/terraform_module_pinned_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/hashicorp/go-getter"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint-ruleset-terraform/project"
"github.com/terraform-linters/tflint-ruleset-terraform/terraform"
)

// TerraformModulePinnedSourceRule checks unpinned or default version module source
Expand Down Expand Up @@ -53,7 +54,9 @@ func (r *TerraformModulePinnedSourceRule) Link() string {

// Check checks if module source version is pinned
// Note that this rule is valid only for Git or Mercurial source
func (r *TerraformModulePinnedSourceRule) Check(runner tflint.Runner) error {
func (r *TerraformModulePinnedSourceRule) Check(rr tflint.Runner) error {
runner := rr.(*terraform.Runner)

path, err := runner.GetModulePath()
if err != nil {
return err
Expand All @@ -69,27 +72,22 @@ func (r *TerraformModulePinnedSourceRule) Check(runner tflint.Runner) error {
return err
}

body, err := runner.GetModuleContent(moduleCallSchema, &tflint.GetModuleContentOption{IncludeNotCreated: true})
if err != nil {
return err
calls, diags := runner.GetModuleCalls()
if diags.HasErrors() {
return diags
}

for _, block := range body.Blocks {
module, diags := decodeModuleCall(block)
if diags.HasErrors() {
return diags
}

if err := r.checkModule(runner, module, config); err != nil {
for _, call := range calls {
if err := r.checkModule(runner, call, config); err != nil {
return err
}
}

return nil
}

func (r *TerraformModulePinnedSourceRule) checkModule(runner tflint.Runner, module *moduleCall, config terraformModulePinnedSourceRuleConfig) error {
source, err := getter.Detect(module.source, filepath.Dir(module.defRange.Filename), []getter.Detector{
func (r *TerraformModulePinnedSourceRule) checkModule(runner tflint.Runner, module *terraform.ModuleCall, config terraformModulePinnedSourceRuleConfig) error {
source, err := getter.Detect(module.Source, filepath.Dir(module.DefRange.Filename), []getter.Detector{
// https://github.com/hashicorp/terraform/blob/51b0aee36cc2145f45f5b04051a01eb6eb7be8bf/internal/getmodules/getter.go#L30-L52
new(getter.GitHubDetector),
new(getter.GitDetector),
Expand Down Expand Up @@ -127,8 +125,8 @@ func (r *TerraformModulePinnedSourceRule) checkModule(runner tflint.Runner, modu
if u.Hostname() == "" {
return runner.EmitIssue(
r,
fmt.Sprintf("Module source %q is not a valid URL", module.source),
module.sourceAttr.Expr.Range(),
fmt.Sprintf("Module source %q is not a valid URL", module.Source),
module.SourceAttr.Expr.Range(),
)
}

Expand All @@ -144,21 +142,21 @@ func (r *TerraformModulePinnedSourceRule) checkModule(runner tflint.Runner, modu

return runner.EmitIssue(
r,
fmt.Sprintf(`Module source "%s" is not pinned`, module.source),
module.sourceAttr.Expr.Range(),
fmt.Sprintf(`Module source "%s" is not pinned`, module.Source),
module.SourceAttr.Expr.Range(),
)
}

func (r *TerraformModulePinnedSourceRule) checkRevision(runner tflint.Runner, module *moduleCall, config terraformModulePinnedSourceRuleConfig, key string, value string) error {
func (r *TerraformModulePinnedSourceRule) checkRevision(runner tflint.Runner, module *terraform.ModuleCall, config terraformModulePinnedSourceRuleConfig, key string, value string) error {
switch config.Style {
// The "flexible" style requires a revision that is not a default branch
case "flexible":
for _, branch := range config.DefaultBranches {
if value == branch {
return runner.EmitIssue(
r,
fmt.Sprintf("Module source \"%s\" uses a default branch as %s (%s)", module.source, key, branch),
module.sourceAttr.Expr.Range(),
fmt.Sprintf("Module source \"%s\" uses a default branch as %s (%s)", module.Source, key, branch),
module.SourceAttr.Expr.Range(),
)
}
}
Expand All @@ -168,8 +166,8 @@ func (r *TerraformModulePinnedSourceRule) checkRevision(runner tflint.Runner, mo
if err != nil {
return runner.EmitIssue(
r,
fmt.Sprintf("Module source \"%s\" uses a %s which is not a semantic version string", module.source, key),
module.sourceAttr.Expr.Range(),
fmt.Sprintf("Module source \"%s\" uses a %s which is not a semantic version string", module.Source, key),
module.SourceAttr.Expr.Range(),
)
}
default:
Expand Down
4 changes: 2 additions & 2 deletions rules/terraform_module_pinned_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,13 +509,13 @@ rule "terraform_module_pinned_source" {

for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
runner := helper.TestRunner(t, map[string]string{"module.tf": tc.Content, ".tflint.hcl": tc.Config})
runner := testRunner(t, map[string]string{"module.tf": tc.Content, ".tflint.hcl": tc.Config})

if err := rule.Check(runner); err != nil {
t.Fatalf("Unexpected error occurred: %s", err)
}

helper.AssertIssues(t, tc.Expected, runner.Issues)
helper.AssertIssues(t, tc.Expected, runner.Runner.(*helper.Runner).Issues)
})
}
}
44 changes: 21 additions & 23 deletions rules/terraform_module_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
tfaddr "github.com/hashicorp/terraform-registry-address"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint-ruleset-terraform/project"
"github.com/terraform-linters/tflint-ruleset-terraform/terraform"
)

// SemVer regexp with optional leading =
Expand Down Expand Up @@ -50,7 +51,9 @@ func (r *TerraformModuleVersionRule) Link() string {

// Check checks whether module source attributes resolve to a Terraform registry
// If they do, it checks a version (or range) is set
func (r *TerraformModuleVersionRule) Check(runner tflint.Runner) error {
func (r *TerraformModuleVersionRule) Check(rr tflint.Runner) error {
runner := rr.(*terraform.Runner)

path, err := runner.GetModulePath()
if err != nil {
return err
Expand All @@ -65,27 +68,22 @@ func (r *TerraformModuleVersionRule) Check(runner tflint.Runner) error {
return err
}

body, err := runner.GetModuleContent(moduleCallSchema, &tflint.GetModuleContentOption{IncludeNotCreated: true})
if err != nil {
return err
calls, diags := runner.GetModuleCalls()
if diags.HasErrors() {
return diags
}

for _, block := range body.Blocks {
module, diags := decodeModuleCall(block)
if diags.HasErrors() {
return diags
}

if err := r.checkModule(runner, module, config); err != nil {
for _, call := range calls {
if err := r.checkModule(runner, call, config); err != nil {
return err
}
}

return nil
}

func (r *TerraformModuleVersionRule) checkModule(runner tflint.Runner, module *moduleCall, config TerraformModuleVersionRuleConfig) error {
_, err := tfaddr.ParseModuleSource(module.source)
func (r *TerraformModuleVersionRule) checkModule(runner tflint.Runner, module *terraform.ModuleCall, config TerraformModuleVersionRuleConfig) error {
_, err := tfaddr.ParseModuleSource(module.Source)
if err != nil {
// If parsing fails, the source does not expect to specify a version,
// such as local or remote. So instead of returning an error,
Expand All @@ -96,32 +94,32 @@ func (r *TerraformModuleVersionRule) checkModule(runner tflint.Runner, module *m
return r.checkVersion(runner, module, config)
}

func (r *TerraformModuleVersionRule) checkVersion(runner tflint.Runner, module *moduleCall, config TerraformModuleVersionRuleConfig) error {
if module.version == nil {
func (r *TerraformModuleVersionRule) checkVersion(runner tflint.Runner, module *terraform.ModuleCall, config TerraformModuleVersionRuleConfig) error {
if module.Version == nil {
return runner.EmitIssue(
r,
fmt.Sprintf("module %q should specify a version", module.name),
module.defRange,
fmt.Sprintf("module %q should specify a version", module.Name),
module.DefRange,
)
}

if !config.Exact {
return nil
}

if len(module.version) > 1 {
if len(module.Version) > 1 {
return runner.EmitIssue(
r,
fmt.Sprintf("module %q should specify an exact version, but multiple constraints were found", module.name),
module.versionAttr.Range,
fmt.Sprintf("module %q should specify an exact version, but multiple constraints were found", module.Name),
module.VersionAttr.Range,
)
}

if !exactVersionRegexp.MatchString(module.version[0].String()) {
if !exactVersionRegexp.MatchString(module.Version[0].String()) {
return runner.EmitIssue(
r,
fmt.Sprintf("module %q should specify an exact version, but a range was found", module.name),
module.versionAttr.Range,
fmt.Sprintf("module %q should specify an exact version, but a range was found", module.Name),
module.VersionAttr.Range,
)
}

Expand Down
8 changes: 4 additions & 4 deletions rules/terraform_module_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,13 @@ module "m" {

for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
runner := helper.TestRunner(t, map[string]string{"module.tf": tc.Content, ".tflint.hcl": tc.Config})
runner := testRunner(t, map[string]string{"module.tf": tc.Content, ".tflint.hcl": tc.Config})

if err := rule.Check(runner); err != nil {
t.Fatalf("Unexpected error occurred: %s", err)
}

helper.AssertIssues(t, tc.Expected, runner.Issues)
helper.AssertIssues(t, tc.Expected, runner.Runner.(*helper.Runner).Issues)
})
}
}
Expand Down Expand Up @@ -220,13 +220,13 @@ func TestTerraformModuleVersion_NonRegistry(t *testing.T) {
for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
content := fmt.Sprintf(testTerraformModuleVersionNonRegistrySource, tc.Source)
runner := helper.TestRunner(t, map[string]string{"module.tf": content})
runner := testRunner(t, map[string]string{"module.tf": content})

if err := rule.Check(runner); err != nil {
t.Fatalf("Unexpected error occurred: %s", err)
}

helper.AssertIssues(t, helper.Issues{}, runner.Issues)
helper.AssertIssues(t, helper.Issues{}, runner.Runner.(*helper.Runner).Issues)
})
}
}
Expand Down
9 changes: 6 additions & 3 deletions rules/terraform_naming_convention.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/terraform-linters/tflint-plugin-sdk/hclext"
"github.com/terraform-linters/tflint-plugin-sdk/tflint"
"github.com/terraform-linters/tflint-ruleset-terraform/project"
"github.com/terraform-linters/tflint-ruleset-terraform/terraform"
)

// TerraformNamingConventionRule checks whether blocks follow naming convention
Expand Down Expand Up @@ -75,7 +76,9 @@ func (r *TerraformNamingConventionRule) Link() string {
}

// Check checks whether blocks follow naming convention
func (r *TerraformNamingConventionRule) Check(runner tflint.Runner) error {
func (r *TerraformNamingConventionRule) Check(rr tflint.Runner) error {
runner := rr.(*terraform.Runner)

path, err := runner.GetModulePath()
if err != nil {
return err
Expand Down Expand Up @@ -198,12 +201,12 @@ func (r *TerraformNamingConventionRule) Check(runner tflint.Runner) error {
if err != nil {
return err
}
locals, diags := getLocals(runner)
locals, diags := runner.GetLocals()
if diags.HasErrors() {
return diags
}
for name, local := range locals {
if err := nameValidator.checkBlock(runner, r, localBlockName, name, &local.defRange); err != nil {
if err := nameValidator.checkBlock(runner, r, localBlockName, name, &local.DefRange); err != nil {
return err
}
}
Expand Down
Loading

0 comments on commit 11c44ac

Please sign in to comment.