Skip to content

Commit eed3c18

Browse files
authored
hclext: Add schema mode to BodySchema (#201)
* Add JustAttributesMode * Add support SchemaMode in gRPC plugin
1 parent 1f55995 commit eed3c18

File tree

9 files changed

+591
-291
lines changed

9 files changed

+591
-291
lines changed

hclext/schema.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,23 @@ import (
77
"strings"
88
)
99

10+
// SchemaMode controls how the body's schema is declared.
11+
//
12+
//go:generate stringer -type=SchemaMode
13+
type SchemaMode int32
14+
15+
const (
16+
// SchemaDefaultMode is a mode for explicitly declaring the structure of attributes and blocks.
17+
SchemaDefaultMode SchemaMode = iota
18+
// SchemaJustAttributesMode is the mode to extract body as attributes.
19+
// In this mode you don't need to declare schema for attributes or blocks.
20+
SchemaJustAttributesMode
21+
)
22+
1023
// BodySchema represents the desired body.
1124
// This structure is designed to have attributes similar to hcl.BodySchema.
1225
type BodySchema struct {
26+
Mode SchemaMode
1327
Attributes []AttributeSchema
1428
Blocks []BlockSchema
1529
}

hclext/schemamode_string.go

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hclext/structure.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package hclext
22

33
import (
4+
"fmt"
45
"reflect"
56

67
"github.com/hashicorp/hcl/v2"
@@ -71,7 +72,16 @@ func Content(body hcl.Body, schema *BodySchema) (*BodyContent, hcl.Diagnostics)
7172
childS[blockS.Type] = blockS.Body
7273
}
7374

74-
content, diags := body.Content(hclS)
75+
content := &hcl.BodyContent{}
76+
var diags hcl.Diagnostics
77+
switch schema.Mode {
78+
case SchemaDefaultMode:
79+
content, diags = body.Content(hclS)
80+
case SchemaJustAttributesMode:
81+
content.Attributes, diags = body.JustAttributes()
82+
default:
83+
panic(fmt.Sprintf("invalid SchemaMode: %s", schema.Mode))
84+
}
7585

7686
ret := &BodyContent{
7787
Attributes: Attributes{},
@@ -127,7 +137,16 @@ func PartialContent(body hcl.Body, schema *BodySchema) (*BodyContent, hcl.Diagno
127137
childS[blockS.Type] = blockS.Body
128138
}
129139

130-
content, _, diags := body.PartialContent(hclS)
140+
content := &hcl.BodyContent{}
141+
var diags hcl.Diagnostics
142+
switch schema.Mode {
143+
case SchemaDefaultMode:
144+
content, _, diags = body.PartialContent(hclS)
145+
case SchemaJustAttributesMode:
146+
content.Attributes, diags = body.JustAttributes()
147+
default:
148+
panic(fmt.Sprintf("invalid SchemaMode: %s", schema.Mode))
149+
}
131150

132151
ret := &BodyContent{
133152
Attributes: Attributes{},

hclext/structure_test.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,127 @@ func TestContent_PartialContent(t *testing.T) {
696696
}
697697
}
698698

699+
func TestContent_JustAttributes(t *testing.T) {
700+
tests := []struct {
701+
Name string
702+
Body *hclsyntax.Body
703+
Schema *BodySchema
704+
Partial bool
705+
Want *BodyContent
706+
DiagCount int
707+
}{
708+
{
709+
Name: "just attributes in the top level",
710+
Body: &hclsyntax.Body{
711+
Attributes: hclsyntax.Attributes{
712+
"foo": &hclsyntax.Attribute{Name: "foo"},
713+
"bar": &hclsyntax.Attribute{Name: "bar"},
714+
"baz": &hclsyntax.Attribute{Name: "baz"},
715+
},
716+
},
717+
Schema: &BodySchema{Mode: SchemaJustAttributesMode},
718+
Want: &BodyContent{
719+
Attributes: Attributes{
720+
"foo": &Attribute{Name: "foo"},
721+
"bar": &Attribute{Name: "bar"},
722+
"baz": &Attribute{Name: "baz"},
723+
},
724+
Blocks: Blocks{},
725+
},
726+
},
727+
{
728+
Name: "just attributes in nested blocks",
729+
Body: &hclsyntax.Body{
730+
Blocks: hclsyntax.Blocks{
731+
&hclsyntax.Block{
732+
Type: "bar",
733+
Body: &hclsyntax.Body{
734+
Attributes: hclsyntax.Attributes{
735+
"foo": &hclsyntax.Attribute{Name: "foo"},
736+
"bar": &hclsyntax.Attribute{Name: "bar"},
737+
"baz": &hclsyntax.Attribute{Name: "baz"},
738+
},
739+
},
740+
},
741+
},
742+
},
743+
Schema: &BodySchema{
744+
Blocks: []BlockSchema{
745+
{
746+
Type: "bar",
747+
Body: &BodySchema{Mode: SchemaJustAttributesMode},
748+
},
749+
},
750+
},
751+
Want: &BodyContent{
752+
Attributes: Attributes{},
753+
Blocks: Blocks{
754+
{
755+
Type: "bar",
756+
Body: &BodyContent{
757+
Attributes: Attributes{
758+
"foo": &Attribute{Name: "foo"},
759+
"bar": &Attribute{Name: "bar"},
760+
"baz": &Attribute{Name: "baz"},
761+
},
762+
Blocks: Blocks{},
763+
},
764+
},
765+
},
766+
},
767+
},
768+
{
769+
Name: "just attributes in body with blocks",
770+
Body: &hclsyntax.Body{
771+
Attributes: hclsyntax.Attributes{
772+
"foo": &hclsyntax.Attribute{Name: "foo"},
773+
"bar": &hclsyntax.Attribute{Name: "bar"},
774+
"baz": &hclsyntax.Attribute{Name: "baz"},
775+
},
776+
Blocks: hclsyntax.Blocks{
777+
&hclsyntax.Block{
778+
Type: "bar",
779+
Body: &hclsyntax.Body{},
780+
},
781+
},
782+
},
783+
Schema: &BodySchema{Mode: SchemaJustAttributesMode},
784+
Want: &BodyContent{
785+
Attributes: Attributes{
786+
"foo": &Attribute{Name: "foo"},
787+
"bar": &Attribute{Name: "bar"},
788+
"baz": &Attribute{Name: "baz"},
789+
},
790+
Blocks: Blocks{},
791+
},
792+
DiagCount: 1, // Unexpected "bar" block; Blocks are not allowed here.
793+
},
794+
}
795+
796+
for _, test := range tests {
797+
t.Run(test.Name, func(t *testing.T) {
798+
var got *BodyContent
799+
var diags hcl.Diagnostics
800+
if test.Partial {
801+
got, diags = PartialContent(test.Body, test.Schema)
802+
} else {
803+
got, diags = Content(test.Body, test.Schema)
804+
}
805+
806+
if len(diags) != test.DiagCount {
807+
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount)
808+
for _, diag := range diags {
809+
t.Logf(" - %s", diag.Error())
810+
}
811+
}
812+
813+
if diff := cmp.Diff(test.Want, got); diff != "" {
814+
t.Errorf("wrong result\ndiff: %s", diff)
815+
}
816+
})
817+
}
818+
}
819+
699820
func Test_IsEmpty(t *testing.T) {
700821
tests := []struct {
701822
name string

plugin/fromproto/fromproto.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,26 @@ func BodySchema(body *proto.BodySchema) *hclext.BodySchema {
3232
}
3333

3434
return &hclext.BodySchema{
35+
Mode: SchemaMode(body.Mode),
3536
Attributes: attributes,
3637
Blocks: blocks,
3738
}
3839
}
3940

41+
// SchemaMode converts proto.SchemaMode to hclext.SchemaMode
42+
func SchemaMode(mode proto.SchemaMode) hclext.SchemaMode {
43+
switch mode {
44+
case proto.SchemaMode_SCHEMA_MODE_UNSPECIFIED:
45+
return hclext.SchemaDefaultMode
46+
case proto.SchemaMode_SCHEMA_MODE_DEFAULT:
47+
return hclext.SchemaDefaultMode
48+
case proto.SchemaMode_SCHEMA_MODE_JUST_ATTRIBUTES:
49+
return hclext.SchemaJustAttributesMode
50+
default:
51+
panic(fmt.Sprintf("invalid SchemaMode: %s", mode))
52+
}
53+
}
54+
4055
// BodyContent converts proto.BodyContent to hclext.BodyContent
4156
func BodyContent(body *proto.BodyContent) (*hclext.BodyContent, hcl.Diagnostics) {
4257
if body == nil {

plugin/plugin2host/plugin2host_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,25 @@ resource "aws_instance" "foo" {
527527
},
528528
ErrCheck: neverHappend,
529529
},
530+
{
531+
Name: "get content as just attributes",
532+
Args: func() (*hclext.BodySchema, *tflint.GetModuleContentOption) {
533+
return &hclext.BodySchema{Mode: hclext.SchemaJustAttributesMode}, nil
534+
},
535+
ServerImpl: func(schema *hclext.BodySchema, opts tflint.GetModuleContentOption) (*hclext.BodyContent, hcl.Diagnostics) {
536+
file := hclFile("test.tf", `
537+
instance_type = "t2.micro"
538+
volume_size = 10`)
539+
return hclext.Content(file.Body, schema)
540+
},
541+
Want: func(schema *hclext.BodySchema, opts *tflint.GetModuleContentOption) (*hclext.BodyContent, hcl.Diagnostics) {
542+
file := hclFile("test.tf", `
543+
instance_type = "t2.micro"
544+
volume_size = 10`)
545+
return hclext.Content(file.Body, schema)
546+
},
547+
ErrCheck: neverHappend,
548+
},
530549
{
531550
Name: "get content with options",
532551
Args: func() (*hclext.BodySchema, *tflint.GetModuleContentOption) {

0 commit comments

Comments
 (0)