Skip to content

Commit b59226d

Browse files
authored
fix(engines): update token parsing to use prefixes
1 parent 300ca18 commit b59226d

File tree

3 files changed

+62
-30
lines changed

3 files changed

+62
-30
lines changed

engines/terraform/resolve.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package terraform
22

33
import (
44
"fmt"
5+
"maps"
6+
"slices"
57
"strings"
68

79
"github.com/aws/jsii-runtime-go"
@@ -11,18 +13,18 @@ import (
1113
func SpecReferenceFromToken(token string) (*SpecReference, error) {
1214
contents, ok := extractTokenContents(token)
1315
if !ok {
14-
return nil, fmt.Errorf("invalid reference format")
16+
return nil, fmt.Errorf("invalid reference format for token: %s", token)
1517
}
1618

1719
parts := strings.Split(contents, ".")
1820
if len(parts) < 2 {
19-
return nil, fmt.Errorf("invalid reference format")
21+
return nil, fmt.Errorf("invalid reference format for token: %s", token)
2022
}
2123

2224
// Validate that all path components are non-empty
2325
for _, part := range parts[1:] {
2426
if part == "" {
25-
return nil, fmt.Errorf("invalid reference format")
27+
return nil, fmt.Errorf("invalid reference format for token: %s", token)
2628
}
2729
}
2830

@@ -87,14 +89,15 @@ func (td *TerraformDeployment) resolveToken(intentName string, specRef *SpecRefe
8789

8890
case "self":
8991
if len(specRef.Path) == 0 {
90-
return nil, fmt.Errorf("references 'self' without specifying a variable. All references must include a variable name e.g. ${self.my_var}")
92+
return nil, fmt.Errorf("references 'self' without specifying a variable. All references must include a variable name e.g. self.my_var")
9193
}
9294

9395
varName := specRef.Path[0]
9496

97+
availableVars := slices.Collect(maps.Keys(td.instancedTerraformVariables[intentName]))
9598
tfVariable, ok := td.instancedTerraformVariables[intentName][varName]
9699
if !ok {
97-
return nil, fmt.Errorf("variable %s does not exist for provided blueprint", varName)
100+
return nil, fmt.Errorf("variable %s does not exist for provided blueprint available variables are: %v", varName, availableVars)
98101
}
99102

100103
if len(specRef.Path) > 1 {

engines/terraform/resolve_test.go

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ func TestSpecReferenceFromToken(t *testing.T) {
1818
}{
1919
{
2020
name: "valid infra reference",
21+
token: "infra.resource.property",
22+
expected: &SpecReference{
23+
Source: "infra",
24+
Path: []string{"resource", "property"},
25+
},
26+
expectError: false,
27+
},
28+
{
29+
name: "valid infra reference with ${} wrapping",
2130
token: "${infra.resource.property}",
2231
expected: &SpecReference{
2332
Source: "infra",
@@ -27,6 +36,15 @@ func TestSpecReferenceFromToken(t *testing.T) {
2736
},
2837
{
2938
name: "valid self reference",
39+
token: "self.my_var",
40+
expected: &SpecReference{
41+
Source: "self",
42+
Path: []string{"my_var"},
43+
},
44+
expectError: false,
45+
},
46+
{
47+
name: "valid self reference with ${} wrapping",
3048
token: "${self.my_var}",
3149
expected: &SpecReference{
3250
Source: "self",
@@ -36,7 +54,7 @@ func TestSpecReferenceFromToken(t *testing.T) {
3654
},
3755
{
3856
name: "valid self reference with nested path",
39-
token: "${self.my_var.nested.value}",
57+
token: "self.my_var.nested.value",
4058
expected: &SpecReference{
4159
Source: "self",
4260
Path: []string{"my_var", "nested", "value"},
@@ -45,7 +63,7 @@ func TestSpecReferenceFromToken(t *testing.T) {
4563
},
4664
{
4765
name: "valid var reference",
48-
token: "${var.platform_var}",
66+
token: "var.platform_var",
4967
expected: &SpecReference{
5068
Source: "var",
5169
Path: []string{"platform_var"},
@@ -54,51 +72,53 @@ func TestSpecReferenceFromToken(t *testing.T) {
5472
},
5573
{
5674
name: "valid var reference with nested path",
57-
token: "${var.platform_var.nested.value}",
75+
token: "var.platform_var.nested.value",
5876
expected: &SpecReference{
5977
Source: "var",
6078
Path: []string{"platform_var", "nested", "value"},
6179
},
6280
expectError: false,
6381
},
6482
{
65-
name: "invalid token format - no closing brace",
66-
token: "${infra.resource",
67-
expected: nil,
68-
expectError: true,
69-
errorMsg: "invalid reference format",
83+
name: "valid token with unclosed brace extracts token",
84+
token: "${infra.resource",
85+
expected: &SpecReference{
86+
Source: "infra",
87+
Path: []string{"resource"},
88+
},
89+
expectError: false,
7090
},
7191
{
7292
name: "invalid token format - not enough parts",
73-
token: "${infra}",
93+
token: "infra",
7494
expected: nil,
7595
expectError: true,
7696
errorMsg: "invalid reference format",
7797
},
7898
{
7999
name: "invalid token format - only source",
80-
token: "${self}",
100+
token: "self",
81101
expected: nil,
82102
expectError: true,
83103
errorMsg: "invalid reference format",
84104
},
85105
{
86106
name: "invalid token format - only var source",
87-
token: "${var}",
107+
token: "var",
88108
expected: nil,
89109
expectError: true,
90110
errorMsg: "invalid reference format",
91111
},
92112
{
93113
name: "invalid token format - self with dot but no path",
94-
token: "${self.}",
114+
token: "self.",
95115
expected: nil,
96116
expectError: true,
97117
errorMsg: "invalid reference format",
98118
},
99119
{
100120
name: "invalid token format - var with dot but no path",
101-
token: "${var.}",
121+
token: "var.",
102122
expected: nil,
103123
expectError: true,
104124
errorMsg: "invalid reference format",
@@ -313,14 +333,14 @@ func TestResolveTokenValue(t *testing.T) {
313333
},
314334
{
315335
name: "single token only",
316-
input: "${self.my_var}",
336+
input: "self.my_var",
317337
setupVar: true,
318338
expectToken: true,
319339
expectError: false,
320340
},
321341
{
322-
name: "string with one token in middle",
323-
input: "prefix-${self.my_var}-suffix",
342+
name: "single token only with ${} wrapping",
343+
input: "${self.my_var}",
324344
setupVar: true,
325345
expectToken: true,
326346
expectError: false,
@@ -385,10 +405,10 @@ func TestResolveStringInterpolation(t *testing.T) {
385405
}{
386406
{
387407
name: "string with two tokens",
388-
input: "prefix-${self.var1}-middle-${self.var2}-suffix",
408+
input: "prefix-${self.var1-middle}-${self.var2-suffix}",
389409
setupVars: map[string]string{
390-
"var1": "value1",
391-
"var2": "value2",
410+
"var1-middle": "value1",
411+
"var2-suffix": "value2",
392412
},
393413
expectError: false,
394414
},
@@ -403,20 +423,29 @@ func TestResolveStringInterpolation(t *testing.T) {
403423
},
404424
{
405425
name: "string with token at start",
406-
input: "${self.var1}-suffix",
426+
input: "self.var1-suffix",
407427
setupVars: map[string]string{
408-
"var1": "value1",
428+
"var1-suffix": "value1",
409429
},
410430
expectError: false,
411431
},
412432
{
413433
name: "string with token at end",
414-
input: "prefix-${self.var1}",
434+
input: "prefix-self.var1",
415435
setupVars: map[string]string{
416436
"var1": "value1",
417437
},
418438
expectError: false,
419439
},
440+
{
441+
name: "string with ${} wrapped tokens",
442+
input: "prefix-${self.var1}-middle-${self.var2}-suffix",
443+
setupVars: map[string]string{
444+
"var1": "value1",
445+
"var2": "value2",
446+
},
447+
expectError: false,
448+
},
420449
}
421450

422451
for _, tt := range tests {

engines/terraform/token.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type TokenMatch struct {
1212
End int
1313
}
1414

15-
// extractTokenContents extracts the contents between ${} from a token string
15+
// extractTokenContents extracts the contents from a token string (infra/var/self prefix)
1616
func extractTokenContents(token string) (string, bool) {
1717
if matches := tokenPattern.FindStringSubmatch(token); len(matches) == 2 {
1818
return matches[1], true
@@ -45,5 +45,5 @@ func isOnlyToken(input string) bool {
4545
return strings.TrimSpace(input) == strings.TrimSpace(allTokensPattern.FindString(input))
4646
}
4747

48-
var tokenPattern = regexp.MustCompile(`^\${([^\s}]+)}$`)
49-
var allTokensPattern = regexp.MustCompile(`\$\{([^\s}]+)\}`)
48+
var tokenPattern = regexp.MustCompile(`((?:infra|var|self)\.[\w.\-]+)`)
49+
var allTokensPattern = regexp.MustCompile(`((?:infra|var|self)\.[\w.\-]+)`)

0 commit comments

Comments
 (0)