Skip to content

Commit 5157b1c

Browse files
committed
add workspace tag extracting
1 parent df0b65c commit 5157b1c

File tree

13 files changed

+324
-53
lines changed

13 files changed

+324
-53
lines changed

attr.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ func (a *expectedAttribute) required() *expectedAttribute {
5151
{
5252
Severity: hcl.DiagError,
5353
Summary: fmt.Sprintf("Missing required attribute %q", a.Key),
54-
Subject: &r,
55-
Extra: nil,
54+
// This is the error word for word from 'terraform apply'
55+
Detail: fmt.Sprintf("The argument %q is required, but no definition is found.", a.Key),
56+
Subject: &r,
57+
Extra: nil,
5658
},
5759
})
5860
}
@@ -79,7 +81,7 @@ func (a *expectedAttribute) expectedTypeError(attr *terraform.Attribute, expecte
7981
{
8082
Severity: hcl.DiagError,
8183
Summary: "Invalid attribute type",
82-
Detail: fmt.Sprintf("The attribute %q must be of type %q, found type %q", attr.Name(), expectedType, attr.Type().FriendlyNameForConstraint()),
84+
Detail: fmt.Sprintf("The attribute %q must be of type %q, found type %q", attr.Name(), expectedType, attr.Type().FriendlyName()),
8385
Subject: &attr.HCLAttribute().Range,
8486
Context: &a.p.block.HCLBlock().DefRange,
8587
Expression: attr.HCLAttribute().Expr,

cli/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (r *RootCmd) Root() *serpent.Command {
4848
Handler: func(i *serpent.Invocation) error {
4949
dfs := os.DirFS(dir)
5050

51-
var rvars map[string]types.ParameterValue
51+
rvars := make(map[string]types.ParameterValue)
5252
for _, val := range vars {
5353
parts := strings.Split(val, "=")
5454
if len(parts) != 2 {

hook.go

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"github.com/coder/preview/hclext"
1414
)
1515

16-
func ParameterContextsEvalHook(input Input, diags hcl.Diagnostics) func(ctx *tfcontext.Context, blocks terraform.Blocks, inputVars map[string]cty.Value) {
16+
func ParameterContextsEvalHook(input Input) func(ctx *tfcontext.Context, blocks terraform.Blocks, inputVars map[string]cty.Value) {
1717
return func(ctx *tfcontext.Context, blocks terraform.Blocks, inputVars map[string]cty.Value) {
1818
data := blocks.OfType("data")
1919
for _, block := range data {
@@ -26,16 +26,15 @@ func ParameterContextsEvalHook(input Input, diags hcl.Diagnostics) func(ctx *tfc
2626
}
2727

2828
name := block.NameLabel()
29-
var defDiags hcl.Diagnostics
3029
var value cty.Value
3130
pv, ok := input.RichParameterValue(name)
3231
if ok {
3332
// TODO: Handle non-string types
3433
value = pv.Value
3534
} else {
3635
// get the default value
37-
value, defDiags = evaluateCoderParameterDefault(block)
38-
diags = diags.Extend(defDiags)
36+
// TODO: Log any diags
37+
value, _ = evaluateCoderParameterDefault(block)
3938
}
4039

4140
// Set the default value as the 'value' attribute
@@ -56,28 +55,16 @@ func evaluateCoderParameterDefault(b *terraform.Block) (cty.Value, hcl.Diagnosti
5655
//}
5756

5857
attributes := b.Attributes()
59-
if attributes == nil {
60-
r := b.HCLBlock().Body.MissingItemRange()
61-
return cty.NilVal, hcl.Diagnostics{
62-
{
63-
Severity: hcl.DiagWarning,
64-
Summary: "'coder_parameter' block has no attributes",
65-
Detail: "No default value will be set for this paramete",
66-
Subject: &r,
67-
},
68-
}
69-
}
70-
7158
var valType cty.Type
7259
var defaults *typeexpr.Defaults
73-
// TODO: `"string"` fails, it should be `string`
60+
7461
typeAttr, exists := attributes["type"]
7562
if exists {
7663
ty, def, err := hclext.DecodeVarType(typeAttr.HCLAttribute().Expr)
7764
if err != nil {
7865
return cty.NilVal, hcl.Diagnostics{
7966
{
80-
Severity: hcl.DiagWarning,
67+
Severity: hcl.DiagError,
8168
Summary: fmt.Sprintf("Decoding parameter type for %q", b.FullName()),
8269
Detail: err.Error(),
8370
Subject: &typeAttr.HCLAttribute().Range,
@@ -112,7 +99,7 @@ func evaluateCoderParameterDefault(b *terraform.Block) (cty.Value, hcl.Diagnosti
11299
if err != nil {
113100
return cty.NilVal, hcl.Diagnostics{
114101
{
115-
Severity: hcl.DiagWarning,
102+
Severity: hcl.DiagError,
116103
Summary: "Converting default parameter value type",
117104
Detail: err.Error(),
118105
Subject: &def.HCLAttribute().Range,

mark.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package preview
2+
3+
import (
4+
"github.com/hashicorp/hcl/v2"
5+
"github.com/zclconf/go-cty/cty"
6+
)
7+
8+
const (
9+
diagnosticsMark = "diagnostics"
10+
)
11+
12+
func markWithDiagnostic(v cty.Value, diag hcl.Diagnostics) cty.Value {
13+
return v.Mark(diag)
14+
}
15+
16+
func valueDiagnostic(v cty.Value) hcl.Diagnostics {
17+
x := v.Marks()
18+
var _ = x
19+
return nil
20+
}

parameter.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ func RichParameters(modules terraform.Modules) ([]types.Parameter, hcl.Diagnosti
3131
}
3232

3333
// Find the value of the parameter from the context.
34-
paramValue, paramValueDiags := richParameterValue(block)
35-
var _ = paramValueDiags // TODO: handle diags for paramValues
34+
paramValue := richParameterValue(block)
3635

3736
param := types.Parameter{
3837
Value: types.ParameterValue{
@@ -45,7 +44,7 @@ func RichParameters(modules terraform.Modules) ([]types.Parameter, hcl.Diagnosti
4544
Mutable: false,
4645
DefaultValue: p.attr("default").string(),
4746
Icon: p.attr("icon").string(),
48-
Options: nil,
47+
Options: paramOptions,
4948
Validation: nil,
5049
Required: false,
5150
DisplayName: "",
@@ -79,7 +78,7 @@ func paramOption(block *terraform.Block) (*types.RichParameterOption, hcl.Diagno
7978
return opt, nil
8079
}
8180

82-
func richParameterValue(block *terraform.Block) (cty.Value, hcl.Diagnostics) {
81+
func richParameterValue(block *terraform.Block) cty.Value {
8382
// Find the value of the parameter from the context.
8483
paramPath := append([]string{"data"}, block.Labels()...)
8584
valueRef := hclext.ScopeTraversalExpr(append(paramPath, "value")...)
@@ -89,8 +88,10 @@ func richParameterValue(block *terraform.Block) (cty.Value, hcl.Diagnostics) {
8988
b := block.HCLBlock().Body.MissingItemRange()
9089
diag.Subject = &b
9190
}
92-
return cty.UnknownVal(cty.NilType), diags
91+
92+
// TODO: Figure out what to do with these diagnostics
93+
return markWithDiagnostic(cty.UnknownVal(cty.NilType), diags)
9394
}
9495

95-
return paramValue, hcl.Diagnostics{}
96+
return paramValue
9697
}

preview.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,13 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (*Output, hcl.Diagnost
2828
return nil, nil
2929
}
3030

31-
diags := make(hcl.Diagnostics, 0)
32-
hook := ParameterContextsEvalHook(input, diags)
31+
hook := ParameterContextsEvalHook(input)
3332
// moduleSource is "" for a local module
3433
p := parser.New(dir, "",
3534
parser.OptionWithDownloads(false),
3635
parser.OptionWithTFVarsPaths(varFiles...),
3736
parser.OptionWithEvalHook(hook),
3837
)
39-
if diags.HasErrors() {
40-
return nil, diags
41-
}
4238

4339
err = p.ParseFS(ctx, ".")
4440
if err != nil {
@@ -63,11 +59,14 @@ func Preview(ctx context.Context, input Input, dir fs.FS) (*Output, hcl.Diagnost
6359
}
6460
var _ = outputs
6561

66-
rp, diags := RichParameters(modules)
62+
diags := make(hcl.Diagnostics, 0)
63+
rp, rpDiags := RichParameters(modules)
64+
tags, tagDiags := WorkspaceTags(modules, p.Files())
6765
return &Output{
68-
Parameters: rp,
69-
Files: p.Files(),
70-
}, diags
66+
Parameters: rp,
67+
WorkspaceTags: tags,
68+
Files: p.Files(),
69+
}, diags.Extend(rpDiags).Extend(tagDiags)
7170
}
7271

7372
func (i Input) RichParameterValue(key string) (types.ParameterValue, bool) {

preview_test.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,21 @@ func Test_Extract(t *testing.T) {
2323
t.Parallel()
2424

2525
for _, tc := range []struct {
26-
name string
27-
dir string
28-
showJSON string
29-
input preview.Input
26+
name string
27+
dir string
28+
showJSON string
29+
failPreview bool
30+
input preview.Input
3031

3132
expTags map[string]string
3233
expUnknowns []string
3334
params map[string]func(t *testing.T, parameter types.Parameter)
3435
}{
36+
{
37+
name: "bad param values",
38+
dir: "badparam",
39+
failPreview: true,
40+
},
3541
{
3642
name: "simple static values",
3743
dir: "static",
@@ -120,7 +126,7 @@ func Test_Extract(t *testing.T) {
120126
params: map[string]func(t *testing.T, parameter types.Parameter){},
121127
},
122128
{
123-
name: "external docker resource",
129+
name: "external docker resource with plan data",
124130
dir: "dockerdata",
125131
showJSON: "show.json",
126132
expTags: map[string]string{
@@ -146,14 +152,17 @@ func Test_Extract(t *testing.T) {
146152
require.NoError(t, err)
147153

148154
output, diags := preview.Preview(context.Background(), tc.input, dirFs)
155+
if tc.failPreview {
156+
require.True(t, diags.HasErrors())
157+
return
158+
}
149159
require.False(t, diags.HasErrors())
150160

151161
// Assert tags
152-
//validTags, err := output.WorkspaceTags.ValidTags()
153-
//require.NoError(t, err)
154-
//
155-
//assert.Equal(t, tc.expTags, validTags)
156-
//assert.ElementsMatch(t, tc.expUnknowns, output.WorkspaceTags.Unknowns())
162+
validTags := output.WorkspaceTags.ValidTags()
163+
164+
assert.Equal(t, tc.expTags, validTags)
165+
assert.ElementsMatch(t, tc.expUnknowns, output.WorkspaceTags.InvalidTags().SafeNames())
157166

158167
// Assert params
159168
require.Len(t, output.Parameters, len(tc.params), "wrong number of parameters expected")

source.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package preview
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/hashicorp/hcl/v2"
8+
)
9+
10+
func source(r hcl.Range, files map[string]*hcl.File) ([]byte, error) {
11+
file, ok := files[r.Filename]
12+
if !ok {
13+
return nil, os.ErrNotExist
14+
}
15+
16+
if len(file.Bytes) < r.End.Byte {
17+
return nil, fmt.Errorf("range end is out of bounds")
18+
}
19+
20+
return file.Bytes[r.Start.Byte:r.End.Byte], nil
21+
}

testdata/badparam/main.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
terraform {
2+
required_providers {
3+
coder = {
4+
source = "coder/coder"
5+
}
6+
}
7+
}
8+
9+
10+
data "coder_parameter" "region" {
11+
}

testdata/dockerdata/main.tf

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@ data "coder_workspace_tags" "custom_workspace_tags" {
1616
tags = {
1717
// If a value is required, you can do something like:
1818
// try(docker_image.ubuntu.repo_digest, "default-value")
19-
"foo" = try(docker_image.ubuntu.repo_digest, "default")
19+
"foo" = docker_image.ubuntu.repo_digest
2020
"bar" = docker_image.centos.repo_digest
2121
"qux" = "quux"
2222
}
2323
}
2424

25-
2625
# Pulls the image
2726
resource "docker_image" "ubuntu" {
2827
name = "ubuntu:latest"

0 commit comments

Comments
 (0)