Skip to content

Commit 8154589

Browse files
committed
fixup some complex variables
1 parent 1af8373 commit 8154589

File tree

4 files changed

+124
-8
lines changed

4 files changed

+124
-8
lines changed

extract/variable.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,37 +42,43 @@ func VariableFromBlock(block *terraform.Block) types.Variable {
4242
}
4343

4444
var val cty.Value
45+
var defSubject hcl.Range
4546
if def, exists := attributes["default"]; exists {
4647
val = def.NullableValue()
48+
defSubject = def.HCLAttribute().Range
4749
}
4850

4951
if valType != cty.NilType {
52+
// TODO: If this code ever extracts the actual value of the variable,
53+
// then we need to source the value from that, rather than the default.
5054
if defaults != nil {
5155
val = defaults.Apply(val)
5256
}
5357

58+
valOK := !val.IsNull() && val.IsWhollyKnown()
5459
typedVal, err := convert.Convert(val, valType)
55-
if err != nil {
56-
var subject hcl.Range
57-
if attributes["default"].HCLAttribute() != nil {
58-
subject = attributes["default"].HCLAttribute().Range
59-
}
60+
if err != nil && valOK {
6061
return types.Variable{
6162
Name: block.Label(),
6263
Diagnostics: hcl.Diagnostics{&hcl.Diagnostic{
6364
Severity: hcl.DiagError,
6465
Summary: fmt.Sprintf("Failed to convert variable default value to type %q for %q",
6566
valType.FriendlyNameForConstraint(), block.Label()),
6667
Detail: err.Error(),
67-
Subject: &subject,
68+
Subject: &defSubject,
6869
}},
6970
}
7071
}
71-
val = typedVal
72+
73+
// If the new converted value is ok, use it.
74+
if err == nil {
75+
val = typedVal
76+
}
7277
} else {
7378
valType = val.Type()
7479
}
7580
return types.Variable{
81+
Name: block.Label(),
7682
Default: val,
7783
Type: valType,
7884
Description: optionalString(block, "description"),

preview_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/zclconf/go-cty/cty"
1717

1818
"github.com/coder/preview"
19+
"github.com/coder/preview/hclext"
1920
"github.com/coder/preview/types"
2021
"github.com/coder/terraform-provider-coder/v2/provider"
2122
)
@@ -43,6 +44,7 @@ func Test_Extract(t *testing.T) {
4344
expTags map[string]string
4445
unknownTags []string
4546
params map[string]assertParam
47+
variables map[string]assertVariable
4648
presets func(t *testing.T, presets []types.Preset)
4749
warnings []*regexp.Regexp
4850
}{
@@ -77,6 +79,17 @@ func Test_Extract(t *testing.T) {
7779
formType(provider.ParameterFormTypeRadio),
7880
"numerical": ap().value("5"),
7981
},
82+
variables: map[string]assertVariable{
83+
"string": av().def(cty.StringVal("Hello, world!")).typeEq(cty.String),
84+
"number": av().def(cty.NumberIntVal(7)).typeEq(cty.Number),
85+
"boolean": av().def(cty.BoolVal(true)).typeEq(cty.Bool),
86+
"coerce_string": av().def(cty.StringVal("5")).typeEq(cty.String),
87+
"complex": av().typeEq(cty.Object(map[string]cty.Type{
88+
"list": cty.List(cty.String),
89+
"name": cty.String,
90+
"age": cty.Number,
91+
})),
92+
},
8093
},
8194
{
8295
name: "conditional-no-inputs",
@@ -637,10 +650,68 @@ func Test_Extract(t *testing.T) {
637650
if tc.presets != nil {
638651
tc.presets(t, output.Presets)
639652
}
653+
654+
// Assert variables
655+
require.Len(t, output.Variables, len(tc.variables), "wrong number of variables expected")
656+
for _, variable := range output.Variables {
657+
check, ok := tc.variables[variable.Name]
658+
require.True(t, ok, "unknown variable %s", variable.Name)
659+
check(t, variable)
660+
}
640661
})
641662
}
642663
}
643664

665+
type assertVariable func(t *testing.T, variable types.Variable)
666+
667+
func av() assertVariable {
668+
return func(t *testing.T, v types.Variable) {
669+
t.Helper()
670+
assert.Empty(t, v.Diagnostics, "variable should have no diagnostics")
671+
}
672+
}
673+
674+
func (a assertVariable) nullable(n bool) assertVariable {
675+
return a.extend(func(t *testing.T, v types.Variable) {
676+
assert.Equal(t, v.Nullable, n, "variable nullable check")
677+
})
678+
}
679+
680+
func (a assertVariable) typeEq(ty cty.Type) assertVariable {
681+
return a.extend(func(t *testing.T, v types.Variable) {
682+
assert.Truef(t, ty.Equals(v.Type), "%q variable type equality check", v.Name)
683+
})
684+
}
685+
686+
func (a assertVariable) def(def cty.Value) assertVariable {
687+
return a.extend(func(t *testing.T, v types.Variable) {
688+
if !assert.Truef(t, def.Equals(v.Default).True(), "%q variable default equality check", v.Name) {
689+
exp, _ := hclext.AsString(def)
690+
got, _ := hclext.AsString(v.Default)
691+
t.Logf("Expected: %s, Value: %s", exp, got)
692+
}
693+
694+
})
695+
}
696+
697+
func (a assertVariable) sensitive(s bool) assertVariable {
698+
return a.extend(func(t *testing.T, v types.Variable) {
699+
assert.Equal(t, v.Sensitive, s, "variable sensitive check")
700+
})
701+
}
702+
703+
func (a assertVariable) ephemeral(e bool) assertVariable {
704+
return a.extend(func(t *testing.T, v types.Variable) {
705+
assert.Equal(t, v.Ephemeral, e, "variable ephemeral check")
706+
})
707+
}
708+
709+
func (a assertVariable) description(d string) assertVariable {
710+
return a.extend(func(t *testing.T, v types.Variable) {
711+
assert.Equal(t, v.Description, d, "variable description check")
712+
})
713+
}
714+
644715
type assertParam func(t *testing.T, parameter types.Parameter)
645716

646717
func ap() assertParam {
@@ -771,3 +842,16 @@ func (a assertParam) extend(f assertParam) assertParam {
771842
f(t, parameter)
772843
}
773844
}
845+
846+
//nolint:revive
847+
func (a assertVariable) extend(f assertVariable) assertVariable {
848+
if a == nil {
849+
a = func(t *testing.T, v types.Variable) {}
850+
}
851+
852+
return func(t *testing.T, v types.Variable) {
853+
t.Helper()
854+
(a)(t, v)
855+
f(t, v)
856+
}
857+
}

testdata/static/main.tf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,32 @@ terraform {
1212
}
1313
}
1414

15+
variable "string" {
16+
default = "Hello, world!"
17+
}
18+
19+
variable "number" {
20+
default = 7
21+
}
22+
23+
variable "boolean" {
24+
default = true
25+
}
26+
27+
variable "coerce_string" {
28+
default = 5 // This will be coerced to a string
29+
type = string
30+
}
31+
32+
variable "complex" {
33+
type = object({
34+
list = list(string)
35+
name = string
36+
age = number
37+
})
38+
}
39+
40+
1541
data "coder_workspace_tags" "custom_workspace_tags" {
1642
tags = {
1743
"zone" = "developers"

variables.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
)
1212

1313
func variables(modules terraform.Modules) []types.Variable {
14-
variableBlocks := modules.GetDatasByType("variable")
14+
variableBlocks := modules.GetBlocks().OfType("variable")
1515
vars := make([]types.Variable, 0, len(variableBlocks))
1616
for _, block := range variableBlocks {
1717
vars = append(vars, extract.VariableFromBlock(block))

0 commit comments

Comments
 (0)