Skip to content

Commit

Permalink
Add variable decoder to earlydecoder
Browse files Browse the repository at this point in the history
  • Loading branch information
Nepomuceno committed May 28, 2021
1 parent 09e92de commit 4ce374b
Show file tree
Hide file tree
Showing 9 changed files with 704 additions and 16 deletions.
7 changes: 6 additions & 1 deletion earlydecoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"github.com/hashicorp/go-version"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform-registry-address"
tfaddr "github.com/hashicorp/terraform-registry-address"
"github.com/hashicorp/terraform-schema/module"
)

Expand Down Expand Up @@ -127,10 +127,15 @@ func LoadModule(path string, files map[string]*hcl.File) (*module.Meta, hcl.Diag
}
}

variables := make(map[string]module.Variable)
for key, variable := range mod.Variables {
variables[key] = *variable
}
return &module.Meta{
Path: path,
ProviderReferences: refs,
ProviderRequirements: providerRequirements,
CoreRequirements: coreRequirements,
Variables: variables,
}, diags
}
140 changes: 132 additions & 8 deletions earlydecoder/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,30 @@ import (
"github.com/hashicorp/go-version"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform-registry-address"
tfaddr "github.com/hashicorp/terraform-registry-address"
"github.com/hashicorp/terraform-schema/module"
"github.com/zclconf/go-cty-debug/ctydebug"
"github.com/zclconf/go-cty/cty"
)

type testCase struct {
name string
cfg string
expectedMeta *module.Meta
}

func TestLoadModule(t *testing.T) {
path := t.TempDir()

testCases := []struct {
name string
cfg string
expectedMeta *module.Meta
}{
testCases := []testCase{
{
"empty config",
``,
&module.Meta{
Path: path,
ProviderReferences: map[module.ProviderRef]tfaddr.Provider{},
ProviderRequirements: map[tfaddr.Provider]version.Constraints{},
Variables: map[string]module.Variable{},
},
},
{
Expand All @@ -40,6 +45,7 @@ terraform {
CoreRequirements: mustConstraints(t, "~> 0.12"),
ProviderReferences: map[module.ProviderRef]tfaddr.Provider{},
ProviderRequirements: map[tfaddr.Provider]version.Constraints{},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -76,6 +82,7 @@ provider "grafana" {
tfaddr.NewLegacyProvider("google"): {},
tfaddr.NewLegacyProvider("grafana"): {},
},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -112,6 +119,7 @@ provider "grafana" {
tfaddr.NewLegacyProvider("google"): mustConstraints(t, ">= 3.0.0"),
tfaddr.NewLegacyProvider("grafana"): {},
},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -152,6 +160,7 @@ provider "grafana" {
tfaddr.NewLegacyProvider("google"): mustConstraints(t, ">= 3.0.0"),
tfaddr.NewLegacyProvider("grafana"): {},
},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -222,6 +231,7 @@ provider "grafana" {
Type: "grafana",
}: mustConstraints(t, "2.1.0"),
},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -282,6 +292,7 @@ resource "google_storage_bucket" "bucket" {
Type: "google",
}: mustConstraints(t, "2.0.0"),
},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -343,6 +354,7 @@ resource "google_storage_bucket" "bucket" {
Type: "google",
}: mustConstraints(t, "2.0.0"),
},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -396,6 +408,7 @@ provider "aws" {
Type: "google",
}: mustConstraints(t, "2.0.0"),
},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -455,6 +468,7 @@ provider "aws" {
Type: "google",
}: mustConstraints(t, "2.0.0"),
},
Variables: map[string]module.Variable{},
},
},
{
Expand Down Expand Up @@ -489,11 +503,114 @@ resource "google_something" "test" {
Type: "google-beta",
}: mustConstraints(t, "2.0.0"),
},
Variables: map[string]module.Variable{},
},
},
}

opts := cmp.Comparer(compareVersionConstraint)
executeTestCases(testCases, t, path)
}

func TestLoadModule_Variables(t *testing.T) {
path := t.TempDir()

testCases := []testCase{
{
"empty variables",
`
variable "name" {
}`,
&module.Meta{
Path: path,
ProviderReferences: map[module.ProviderRef]tfaddr.Provider{},
ProviderRequirements: map[tfaddr.Provider]version.Constraints{},
Variables: map[string]module.Variable{
"name": {
Type: cty.DynamicPseudoType,
},
},
},
},
{
"variables with type",
`
variable "name" {
type = string
}`,
&module.Meta{
Path: path,
ProviderReferences: map[module.ProviderRef]tfaddr.Provider{},
ProviderRequirements: map[tfaddr.Provider]version.Constraints{},
Variables: map[string]module.Variable{
"name": {
Type: cty.String,
},
},
},
},
{
"variables with description",
`
variable "name" {
description = "description"
}`,
&module.Meta{
Path: path,
ProviderReferences: map[module.ProviderRef]tfaddr.Provider{},
ProviderRequirements: map[tfaddr.Provider]version.Constraints{},
Variables: map[string]module.Variable{
"name": {
Type: cty.DynamicPseudoType,
Description: "description",
},
},
},
},
{
"variables with sensitive",
`
variable "name" {
sensitive = true
}`,
&module.Meta{
Path: path,
ProviderReferences: map[module.ProviderRef]tfaddr.Provider{},
ProviderRequirements: map[tfaddr.Provider]version.Constraints{},
Variables: map[string]module.Variable{
"name": {
Type: cty.DynamicPseudoType,
IsSensitive: true,
},
},
},
},
{
"variables with type and description and sensitive",
`
variable "name" {
type = string
description = "description"
sensitive = true
}`,
&module.Meta{
Path: path,
ProviderReferences: map[module.ProviderRef]tfaddr.Provider{},
ProviderRequirements: map[tfaddr.Provider]version.Constraints{},
Variables: map[string]module.Variable{
"name": {
Type: cty.String,
Description: "description",
IsSensitive: true,
},
},
},
},
}
executeTestCases(testCases, t, path)

}
func executeTestCases(testCases []testCase, t *testing.T, path string) {
opts := getCustomComparers()

for i, tc := range testCases {
t.Run(fmt.Sprintf("%d-%s", i, tc.name), func(t *testing.T) {
Expand All @@ -510,7 +627,7 @@ resource "google_something" "test" {
t.Fatal(diags)
}

if diff := cmp.Diff(tc.expectedMeta, meta, opts); diff != "" {
if diff := cmp.Diff(tc.expectedMeta, meta, opts...); diff != "" {
t.Fatalf("module meta doesn't match: %s", diff)
}
})
Expand All @@ -528,3 +645,10 @@ func mustConstraints(t *testing.T, vc string) version.Constraints {
func compareVersionConstraint(x, y version.Constraint) bool {
return x.String() == y.String()
}

func getCustomComparers() []cmp.Option {
return []cmp.Option{
cmp.Comparer(compareVersionConstraint),
ctydebug.CmpOptions,
}
}
40 changes: 36 additions & 4 deletions earlydecoder/load_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform-schema/internal/typeexpr"
"github.com/hashicorp/terraform-schema/module"
"github.com/zclconf/go-cty/cty"
)

// decodedModule is the type representing a decoded Terraform module.
Expand All @@ -16,15 +18,17 @@ type decodedModule struct {
ProviderConfigs map[string]*providerConfig
Resources map[string]*resource
DataSources map[string]*dataSource
Variables map[string]*module.Variable
}

func newDecodedModule() *decodedModule {
return &decodedModule{
RequiredCore: make([]string, 0),
ProviderRequirements: make(map[string]*providerRequirement, 0),
ProviderConfigs: make(map[string]*providerConfig, 0),
Resources: make(map[string]*resource, 0),
DataSources: make(map[string]*dataSource, 0),
ProviderRequirements: make(map[string]*providerRequirement),
ProviderConfigs: make(map[string]*providerConfig),
Resources: make(map[string]*resource),
DataSources: make(map[string]*dataSource),
Variables: make(map[string]*module.Variable),
}
}

Expand Down Expand Up @@ -166,7 +170,35 @@ func loadModuleFromFile(file *hcl.File, mod *decodedModule) hcl.Diagnostics {
LocalName: inferProviderNameFromType(r.Type),
}
}

case "variable":
content, _, contentDiags := block.Body.PartialContent(variableSchema)
diags = append(diags, contentDiags...)
name := block.Labels[0]
description := ""
isSensitive := false
var valDiags hcl.Diagnostics
if attr, defined := content.Attributes["description"]; defined {
valDiags = gohcl.DecodeExpression(attr.Expr, nil, &description)
diags = append(diags, valDiags...)
}
varType := cty.DynamicPseudoType
if attr, defined := content.Attributes["type"]; defined {
varType, valDiags = typeexpr.TypeConstraint(attr.Expr)
diags = append(diags, valDiags...)
}
if attr, defined := content.Attributes["sensitive"]; defined {
valDiags = gohcl.DecodeExpression(attr.Expr, nil, &isSensitive)
diags = append(diags, valDiags...)
}
mod.Variables[name] = &module.Variable{
Type: varType,
Description: description,
IsSensitive: isSensitive,
}

}

}

return diags
Expand Down
21 changes: 21 additions & 0 deletions earlydecoder/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ var rootSchema = &hcl.BodySchema{
Type: "data",
LabelNames: []string{"type", "name"},
},
{
Type: "variable",
LabelNames: []string{"name"},
},
},
}

Expand Down Expand Up @@ -55,3 +59,20 @@ var resourceSchema = &hcl.BodySchema{
},
},
}

var variableSchema = &hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{
Name: "description",
},
{
Name: "type",
},
{
Name: "sensitive",
},
{
Name: "default",
},
},
}
10 changes: 10 additions & 0 deletions internal/typeexpr/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Package typeexpr is a fork of github.com/hashicorp/hcl/v2/ext/typeexpr
// which has additional experimental support for optional attributes.
//
// This is here as part of the module_variable_optional_attrs experiment.
// If that experiment is successful, the changes here may be upstreamed into
// HCL itself or, if we deem it to be Terraform-specific, we should at least
// update this documentation to reflect that this is now the primary
// Terraform-specific type expression implementation, separate from the
// upstream HCL one.
package typeexpr
Loading

0 comments on commit 4ce374b

Please sign in to comment.