Skip to content

Commit 709fcda

Browse files
committed
Implement WalkModuleCalls in the test helper Runner
It's fairly minimal and of course doesn't enforce the vast majority of the rules that Terraform would while processing a module call block, but it hits the highlights.
1 parent f4dbe3b commit 709fcda

File tree

1 file changed

+134
-12
lines changed

1 file changed

+134
-12
lines changed

helper/runner.go

Lines changed: 134 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package helper
22

33
import (
4+
"github.com/hashicorp/go-version"
45
"github.com/hashicorp/hcl/v2"
56
"github.com/hashicorp/hcl/v2/gohcl"
67
"github.com/terraform-linters/tflint-plugin-sdk/terraform"
@@ -137,6 +138,32 @@ func (r *Runner) WalkResources(resourceType string, walker func(*terraform.Resou
137138

138139
// WalkModuleCalls visits all module calls from Files.
139140
func (r *Runner) WalkModuleCalls(walker func(*terraform.ModuleCall) error) error {
141+
for _, file := range r.Files {
142+
calls, _, diags := file.Body.PartialContent(&hcl.BodySchema{
143+
Blocks: []hcl.BlockHeaderSchema{
144+
{
145+
Type: "module",
146+
LabelNames: []string{"name"},
147+
},
148+
},
149+
})
150+
if diags.HasErrors() {
151+
return diags
152+
}
153+
154+
for _, block := range calls.Blocks {
155+
call, diags := simpleDecodeModuleCallBlock(block)
156+
if diags.HasErrors() {
157+
return diags
158+
}
159+
160+
err := walker(call)
161+
if err != nil {
162+
return err
163+
}
164+
}
165+
}
166+
140167
return nil
141168
}
142169

@@ -256,21 +283,10 @@ func simpleDecodeResouceBlock(resource *hcl.Block) (*terraform.Resource, hcl.Dia
256283

257284
var ref *terraform.ProviderConfigRef
258285
if attr, exists := content.Attributes["provider"]; exists {
259-
traversal, diags := hcl.AbsTraversalForExpr(attr.Expr)
286+
ref, diags = decodeProviderConfigRef(attr.Expr)
260287
if diags.HasErrors() {
261288
return nil, diags
262289
}
263-
264-
ref = &terraform.ProviderConfigRef{
265-
Name: traversal.RootName(),
266-
NameRange: traversal[0].SourceRange(),
267-
}
268-
269-
if len(traversal) > 1 {
270-
aliasStep := traversal[1].(hcl.TraverseAttr)
271-
ref.Alias = aliasStep.Name
272-
ref.AliasRange = aliasStep.SourceRange().Ptr()
273-
}
274290
}
275291

276292
managed := &terraform.ManagedResource{}
@@ -384,3 +400,109 @@ func simpleDecodeResouceBlock(resource *hcl.Block) (*terraform.Resource, hcl.Dia
384400
TypeRange: resource.LabelRanges[0],
385401
}, nil
386402
}
403+
404+
func simpleDecodeModuleCallBlock(block *hcl.Block) (*terraform.ModuleCall, hcl.Diagnostics) {
405+
content, remain, diags := block.Body.PartialContent(&hcl.BodySchema{
406+
Attributes: []hcl.AttributeSchema{
407+
{Name: "source", Required: true},
408+
{Name: "version"},
409+
{Name: "providers"},
410+
},
411+
})
412+
if diags.HasErrors() {
413+
return nil, diags
414+
}
415+
416+
var sourceAddr string
417+
var sourceAddrRange hcl.Range
418+
if attr, exists := content.Attributes["source"]; exists {
419+
if diags := gohcl.DecodeExpression(attr.Expr, nil, &sourceAddr); diags.HasErrors() {
420+
return nil, diags
421+
}
422+
sourceAddrRange = attr.Expr.Range()
423+
}
424+
425+
providers := []terraform.PassedProviderConfig{}
426+
if attr, exists := content.Attributes["providers"]; exists {
427+
pairs, diags := hcl.ExprMap(attr.Expr)
428+
if diags.HasErrors() {
429+
return nil, diags
430+
}
431+
432+
for _, pair := range pairs {
433+
key, diags := decodeProviderConfigRef(pair.Key)
434+
if diags.HasErrors() {
435+
return nil, diags
436+
}
437+
438+
value, diags := decodeProviderConfigRef(pair.Value)
439+
if diags.HasErrors() {
440+
return nil, diags
441+
}
442+
443+
providers = append(providers, terraform.PassedProviderConfig{
444+
InChild: key,
445+
InParent: value,
446+
})
447+
}
448+
}
449+
450+
var versionRequired version.Constraints
451+
var versionValue string
452+
var versionRange hcl.Range
453+
var err error
454+
if attr, exists := content.Attributes["version"]; exists {
455+
versionRange = attr.Expr.Range()
456+
457+
if diags := gohcl.DecodeExpression(attr.Expr, nil, &versionValue); diags.HasErrors() {
458+
return nil, diags
459+
}
460+
461+
versionRequired, err = version.NewConstraint(versionValue)
462+
if err != nil {
463+
return nil, hcl.Diagnostics{
464+
{Severity: hcl.DiagError, Summary: "Invalid version constraint"},
465+
}
466+
}
467+
}
468+
469+
return &terraform.ModuleCall{
470+
Name: block.Labels[0],
471+
472+
SourceAddr: sourceAddr,
473+
SourceAddrRange: sourceAddrRange,
474+
SourceSet: !sourceAddrRange.Empty(),
475+
476+
Config: remain,
477+
ConfigRange: block.DefRange,
478+
479+
Version: terraform.VersionConstraint{
480+
Required: versionRequired,
481+
DeclRange: versionRange,
482+
},
483+
484+
Providers: providers,
485+
486+
DeclRange: block.DefRange,
487+
}, nil
488+
}
489+
490+
func decodeProviderConfigRef(expr hcl.Expression) (*terraform.ProviderConfigRef, hcl.Diagnostics) {
491+
traversal, diags := hcl.AbsTraversalForExpr(expr)
492+
if diags.HasErrors() {
493+
return nil, diags
494+
}
495+
496+
ref := &terraform.ProviderConfigRef{
497+
Name: traversal.RootName(),
498+
NameRange: traversal[0].SourceRange(),
499+
}
500+
501+
if len(traversal) > 1 {
502+
aliasStep := traversal[1].(hcl.TraverseAttr)
503+
ref.Alias = aliasStep.Name
504+
ref.AliasRange = aliasStep.SourceRange().Ptr()
505+
}
506+
507+
return ref, nil
508+
}

0 commit comments

Comments
 (0)