Skip to content

Commit a6a54a4

Browse files
authored
Merge pull request #40 from terraform-linters/add_walk_blocks_helper
helper: Add WalkResourceBlocks helper
2 parents 5f397e1 + 1ec9561 commit a6a54a4

File tree

2 files changed

+114
-11
lines changed

2 files changed

+114
-11
lines changed

helper/runner.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,49 @@ func (r *Runner) WalkResourceAttributes(resourceType, attributeName string, walk
5757
return nil
5858
}
5959

60+
// WalkResourceBlocks visits all specified blocks from Files.
61+
func (r *Runner) WalkResourceBlocks(resourceType, blockType string, walker func(*hcl.Block) error) error {
62+
for _, file := range r.Files {
63+
resources, _, diags := file.Body.PartialContent(&hcl.BodySchema{
64+
Blocks: []hcl.BlockHeaderSchema{
65+
{
66+
Type: "resource",
67+
LabelNames: []string{"type", "name"},
68+
},
69+
},
70+
})
71+
if diags.HasErrors() {
72+
return diags
73+
}
74+
75+
for _, resource := range resources.Blocks {
76+
if resource.Labels[0] != resourceType {
77+
continue
78+
}
79+
80+
body, _, diags := resource.Body.PartialContent(&hcl.BodySchema{
81+
Blocks: []hcl.BlockHeaderSchema{
82+
{
83+
Type: blockType,
84+
},
85+
},
86+
})
87+
if diags.HasErrors() {
88+
return diags
89+
}
90+
91+
for _, block := range body.Blocks {
92+
err := walker(block)
93+
if err != nil {
94+
return err
95+
}
96+
}
97+
}
98+
}
99+
100+
return nil
101+
}
102+
60103
// WalkResources visits all specified resources from Files.
61104
func (r *Runner) WalkResources(resourceType string, walker func(*terraform.Resource) error) error {
62105
for _, file := range r.Files {

helper/runner_test.go

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,66 @@ resource "aws_s3_bucket" "bar" {
6060
}
6161
}
6262

63+
func Test_WalkResourceBlocks(t *testing.T) {
64+
src := `
65+
resource "aws_instance" "foo" {
66+
ami = "ami-123456"
67+
ebs_block_device {
68+
volume_size = 16
69+
}
70+
}
71+
72+
resource "aws_s3_bucket" "bar" {
73+
bucket = "my-tf-test-bucket"
74+
acl = "private"
75+
}`
76+
77+
runner := TestRunner(t, map[string]string{"main.tf": src})
78+
79+
walked := []*hcl.Block{}
80+
walker := func(block *hcl.Block) error {
81+
walked = append(walked, block)
82+
return nil
83+
}
84+
85+
if err := runner.WalkResourceBlocks("aws_instance", "ebs_block_device", walker); err != nil {
86+
t.Fatal(err)
87+
}
88+
89+
expected := []*hcl.Block{
90+
{
91+
Type: "ebs_block_device",
92+
Body: &hclsyntax.Body{
93+
Attributes: hclsyntax.Attributes{
94+
"volume_size": {
95+
Name: "volume_size",
96+
Expr: &hclsyntax.LiteralValueExpr{
97+
SrcRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 5, Column: 19}, End: hcl.Pos{Line: 5, Column: 21}},
98+
},
99+
SrcRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 5, Column: 5}, End: hcl.Pos{Line: 5, Column: 21}},
100+
NameRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 5, Column: 5}, End: hcl.Pos{Line: 5, Column: 16}},
101+
EqualsRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 5, Column: 17}, End: hcl.Pos{Line: 5, Column: 18}},
102+
},
103+
},
104+
Blocks: hclsyntax.Blocks{},
105+
SrcRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 4, Column: 20}, End: hcl.Pos{Line: 6, Column: 4}},
106+
EndRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 6, Column: 4}, End: hcl.Pos{Line: 6, Column: 4}},
107+
},
108+
DefRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 4, Column: 3}, End: hcl.Pos{Line: 4, Column: 19}},
109+
TypeRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 4, Column: 3}, End: hcl.Pos{Line: 4, Column: 19}},
110+
},
111+
}
112+
113+
opts := cmp.Options{
114+
cmpopts.IgnoreFields(hclsyntax.LiteralValueExpr{}, "Val"),
115+
cmpopts.IgnoreFields(hcl.Pos{}, "Byte"),
116+
cmpopts.IgnoreUnexported(hclsyntax.Body{}),
117+
}
118+
if !cmp.Equal(expected, walked, opts...) {
119+
t.Fatalf("Diff: %s", cmp.Diff(expected, walked, opts...))
120+
}
121+
}
122+
63123
func Test_WalkResources(t *testing.T) {
64124
src := `
65125
resource "aws_instance" "foo" {
@@ -144,12 +204,12 @@ resource "aws_s3_bucket" "bar" {
144204
create_before_destroy = true
145205
prevent_destroy = true
146206
ignore_changes = all
147-
}`, "main.tf",
148-
hcl.Pos{Line: 3, Column: 3},
207+
}`, "main.tf",
208+
hcl.Pos{Line: 3, Column: 3},
149209
hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 2, Column: 31}, End: hcl.Pos{Line: 31, Column: 2}},
150210
hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 31, Column: 2}, End: hcl.Pos{Line: 31, Column: 2}},
151211
),
152-
Count: parseExpression(t, `1`, "main.tf", hcl.Pos{Line: 5, Column: 11}),
212+
Count: parseExpression(t, `1`, "main.tf", hcl.Pos{Line: 5, Column: 11}),
153213
ForEach: parseExpression(t, `{
154214
foo = "bar"
155215
}`, "main.tf", hcl.Pos{Line: 6, Column: 14}),
@@ -164,7 +224,7 @@ resource "aws_s3_bucket" "bar" {
164224
Managed: &terraform.ManagedResource{
165225
Connection: &terraform.Connection{
166226
Config: parseBody(
167-
t,
227+
t,
168228
`type = "ssh"`,
169229
"main.tf",
170230
hcl.Pos{Line: 13, Column: 5},
@@ -175,9 +235,9 @@ resource "aws_s3_bucket" "bar" {
175235
},
176236
Provisioners: []*terraform.Provisioner{
177237
{
178-
Type: "local-exec",
238+
Type: "local-exec",
179239
Config: parseBody(
180-
t,
240+
t,
181241
`command = "chmod 600 ssh-key.pem"
182242
when = destroy
183243
on_failure = continue
@@ -192,7 +252,7 @@ resource "aws_s3_bucket" "bar" {
192252
),
193253
Connection: &terraform.Connection{
194254
Config: parseBody(
195-
t,
255+
t,
196256
`type = "ssh"`,
197257
"main.tf",
198258
hcl.Pos{Line: 22, Column: 7},
@@ -201,10 +261,10 @@ resource "aws_s3_bucket" "bar" {
201261
),
202262
DeclRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 21, Column: 5}, End: hcl.Pos{Line: 21, Column: 15}},
203263
},
204-
When: terraform.ProvisionerWhenDestroy,
205-
OnFailure: terraform.ProvisionerOnFailureContinue,
206-
DeclRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 16, Column: 3}, End: hcl.Pos{Line: 16, Column: 27}},
207-
TypeRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 16, Column: 15}, End: hcl.Pos{Line: 16, Column: 27}},
264+
When: terraform.ProvisionerWhenDestroy,
265+
OnFailure: terraform.ProvisionerOnFailureContinue,
266+
DeclRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 16, Column: 3}, End: hcl.Pos{Line: 16, Column: 27}},
267+
TypeRange: hcl.Range{Filename: "main.tf", Start: hcl.Pos{Line: 16, Column: 15}, End: hcl.Pos{Line: 16, Column: 27}},
208268
},
209269
},
210270

0 commit comments

Comments
 (0)