Skip to content

Commit

Permalink
Add escaping of triple-braces.
Browse files Browse the repository at this point in the history
Fix exec step with list of commands directly underneath.

Signed-off-by: Mathieu Frenette <[email protected]>
  • Loading branch information
silphid committed Feb 9, 2021
1 parent e66a3a2 commit 5daa6c4
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 10 deletions.
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@
Code generator and script runner.

## Wishlist (if time allows)
## Wishlist

- When prompting again, reuse existing values as defaults
- Per-template/module scripts in `bin` dir, which are automatically included in `PATH`
- `jen exec` and `jen export` should alter `PATH` to include `bin` dir(s)
- `jen do` alone to prompt for action
- `jen export` to list env variables
- Reusable modules
- Add `set` step to set multiple variables (are those saved to `jen.yaml`?)
- Override values at command-line level (`--set myValue=value`)
- Exceptionally escape within any file, using `{{{` and `}}}` to represent `{{` and `}}`
- `confirm` step (similar to `if`, but `confirm` property contains message to display and `then` the steps to execute)
- Custom placeholders:

Expand Down
8 changes: 8 additions & 0 deletions src/internal/evaluation/evaluation.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ func EvalBoolExpression(values model.Values, expression string) (bool, error) {
// EvalPromptValueTemplate interpolates a choice or default value string that will be presented to
// user via a prompt, by evaluating both go template expressions and $... shell expressions
func EvalPromptValueTemplate(values model.Values, binDirs []string, text string) (string, error) {
// Escape triple braces
doubleOpen := strings.Repeat("{", 2)
doubleClose := strings.Repeat("}", 2)
tripleOpen := strings.Repeat("{", 3)
tripleClose := strings.Repeat("}", 3)
text = strings.ReplaceAll(text, tripleOpen, doubleOpen+"`"+doubleOpen+"`"+doubleClose)
text = strings.ReplaceAll(text, tripleClose, doubleOpen+"`"+doubleClose+"`"+doubleClose)

// Interpolate go templating
str, err := EvalTemplate(values, text)
if err != nil {
Expand Down
7 changes: 6 additions & 1 deletion src/internal/evaluation/evaluation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,16 @@ func TestEvalPromptValueTemplate(t *testing.T) {
Value: `Hello {{"$VAR1"}} World`,
Expected: `Hello value1 World`,
},
{
Name: "Ignore escaped triple braces",
Value: `Hello {{{ .VAR }}} World`,
Expected: `Hello {{ .VAR }} World`,
},
}

for _, f := range fixtures {
t.Run(f.Name, func(t *testing.T) {
actual, err := EvalPromptValueTemplate(values, "", f.Value)
actual, err := EvalPromptValueTemplate(values, nil, f.Value)
assert.NoError(t, err)
assert.Equal(t, f.Expected, actual)
})
Expand Down
29 changes: 27 additions & 2 deletions src/internal/persist/loadHelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ func getOptionalMap(node yaml.Node, key string) (yaml.Map, bool, error) {
return m, true, nil
}

// getOptionalMapOrRawString retrieves the child map with given key or, if child is a raw string, it returns a map with
// getOptionalMapOrRawStringOrRawStrings retrieves the child map with given key or, if child is a raw string, it returns a map with
// raw string stored in a property keyed with defaultSubKey. This is to support steps that have two alternate syntaxes,
// a long-hand syntax using a map with multiple properties and a short-hand syntax with a raw string that specifies
// only the value of defaultSubKey. If defaultSubKey is an empty string, then only the long-hand map syntax is tried.
func getOptionalMapOrRawString(node yaml.Node, key, defaultSubKey string) (yaml.Map, bool, error) {
func getOptionalMapOrRawStringOrRawStrings(node yaml.Node, key, defaultSubKey string) (yaml.Map, bool, error) {
_map, ok := node.(yaml.Map)
if !ok {
return nil, false, nil
Expand All @@ -63,6 +63,15 @@ func getOptionalMapOrRawString(node yaml.Node, key, defaultSubKey string) (yaml.
}
return _map, true, nil
}

// Try list of raw strings
list := getOptionalListOfScalar(child)
if list != nil {
_map = yaml.Map{
defaultSubKey: list,
}
return _map, true, nil
}
}

// Try map
Expand Down Expand Up @@ -172,6 +181,22 @@ func getString(node yaml.Node) (string, bool) {
return str, true
}

func getOptionalListOfScalar(node yaml.Node) yaml.List {
list, ok := node.(yaml.List)
if !ok {
return nil
}

// Ensure all list children are scalars
for _, item := range list {
if _, ok := item.(yaml.Scalar); !ok {
return nil
}
}

return list
}

func getOptionalBool(_map yaml.Map, key string, defaultValue bool) (bool, error) {
value, ok, err := getStringInternal(_map, key)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion src/internal/persist/loadSpec.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func loadExecutable(node yaml.Node) (model.Executable, error) {
}

for _, x := range items {
_map, ok, err := getOptionalMapOrRawString(node, x.name, x.defaultSubKey)
_map, ok, err := getOptionalMapOrRawStringOrRawStrings(node, x.name, x.defaultSubKey)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 5daa6c4

Please sign in to comment.