Skip to content

Commit

Permalink
Add test.Required function
Browse files Browse the repository at this point in the history
Signed-off-by: Dave Henderson <[email protected]>
  • Loading branch information
hairyhenderson committed Sep 7, 2018
1 parent 955fc69 commit 4f655be
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 0 deletions.
40 changes: 40 additions & 0 deletions docs-src/content/functions/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,43 @@ funcs:
template: <arg>:1:3: executing "<arg>" at <fail>: error calling fail: template generation failed
$ gomplate -i '{{ test.Fail "something is wrong!" }}'
template: <arg>:1:7: executing "<arg>" at <test.Fail>: error calling Fail: template generation failed: something is wrong!
- name: test.Required
alias: required
description: |
Passes through the given value, if it's non-empty, non-zero, and non-`nil`.
Otherwise, exits and prints a given error message so the user can adjust as
necessary.
This is particularly useful for cases where templates require user-provided
data (such as datasources or environment variables), and rendering can not
continue correctly.
This was inspired by [Helm's `required` function](https://github.com/kubernetes/helm/blob/master/docs/charts_tips_and_tricks.md#know-your-template-functions),
but has slightly different behaviour. Notably, gomplate will always fail in
cases where a referenced _key_ is missing, and this function will have no
effect.
pipeline: true
arguments:
- name: message
required: false
description: The optional message to provide when the required value is not provided
- name: value
required: true
description: The required value
examples:
- |
$ FOO=foobar gomplate -i '{{ getenv "FOO" | required "Missing FOO environment variable!" }}'
foobar
$ FOO= gomplate -i '{{ getenv "FOO" | required "Missing FOO environment variable!" }}'
error: Missing FOO environment variable!
- |
$ cat <<EOF> config.yaml
defined: a value
empty: ""
EOF
$ gomplate -d config=config.yaml -i '{{ (ds "config").defined | required "The `config` datasource must have a value defined for `defined`" }}'
a value
$ gomplate -d config=config.yaml -i '{{ (ds "config").empty | required "The `config` datasource must have a value defined for `empty`" }}'
template: <arg>:1:25: executing "<arg>" at <required "The `confi...>: error calling required: The `config` datasource must have a value defined for `empty`
$ gomplate -d config=config.yaml -i '{{ (ds "config").bogus | required "The `config` datasource must have a value defined for `bogus`" }}'
template: <arg>:1:7: executing "<arg>" at <"config">: map has no entry for key "bogus"
18 changes: 18 additions & 0 deletions docs/content/functions/conv.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ $ gomplate -i '{{ "" | default "foo" }} {{ "bar" | default "baz" }}'
foo bar
```

## `conv.Required`

**Alias:** `required`

The `required` function allows you to declare a particular values entry as
required for template rendering. If the value is empty, the template rendering
will fail with a user submitted error message.

This was inspired by, and behaves the same as [Helm's `required` function](https://github.com/kubernetes/helm/blob/master/docs/charts_tips_and_tricks.md#know-your-template-functions).

#### Example

value: {{required "A valid .Values.who entry required!" .Values.who }}
```console
$ gomplate -i '{{ required "Missing $FOO environment variable!" .Env.FOO }}'
foo bar
```

## `conv.Slice`

**Alias:** `slice`
Expand Down
54 changes: 54 additions & 0 deletions docs/content/functions/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,57 @@ template: <arg>:1:3: executing "<arg>" at <fail>: error calling fail: template g
$ gomplate -i '{{ test.Fail "something is wrong!" }}'
template: <arg>:1:7: executing "<arg>" at <test.Fail>: error calling Fail: template generation failed: something is wrong!
```

## `test.Required`

**Alias:** `required`

Passes through the given value, if it's non-empty, non-zero, and non-`nil`.
Otherwise, exits and prints a given error message so the user can adjust as
necessary.

This is particularly useful for cases where templates require user-provided
data (such as datasources or environment variables), and rendering can not
continue correctly.

This was inspired by [Helm's `required` function](https://github.com/kubernetes/helm/blob/master/docs/charts_tips_and_tricks.md#know-your-template-functions),
but has slightly different behaviour. Notably, gomplate will always fail in
cases where a referenced _key_ is missing, and this function will have no
effect.

### Usage
```go
test.Required [message] value
```

```go
value | test.Required [message]
```

### Arguments

| name | description |
|------|-------------|
| `message` | _(optional)_ The optional message to provide when the required value is not provided |
| `value` | _(required)_ The required value |

### Examples

```console
$ FOO=foobar gomplate -i '{{ getenv "FOO" | required "Missing FOO environment variable!" }}'
foobar
$ FOO= gomplate -i '{{ getenv "FOO" | required "Missing FOO environment variable!" }}'
error: Missing FOO environment variable!
```
```console
$ cat <<EOF> config.yaml
defined: a value
empty: ""
EOF
$ gomplate -d config=config.yaml -i '{{ (ds "config").defined | required "The `config` datasource must have a value defined for `defined`" }}'
a value
$ gomplate -d config=config.yaml -i '{{ (ds "config").empty | required "The `config` datasource must have a value defined for `empty`" }}'
template: <arg>:1:25: executing "<arg>" at <required "The `confi...>: error calling required: The `config` datasource must have a value defined for `empty`
$ gomplate -d config=config.yaml -i '{{ (ds "config").bogus | required "The `config` datasource must have a value defined for `bogus`" }}'
template: <arg>:1:7: executing "<arg>" at <"config">: map has no entry for key "bogus"
```
17 changes: 17 additions & 0 deletions funcs/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func AddTestFuncs(f map[string]interface{}) {

f["assert"] = TestNS().Assert
f["fail"] = TestNS().Fail
f["required"] = TestNS().Required
}

// TestFuncs -
Expand Down Expand Up @@ -59,3 +60,19 @@ func (f *TestFuncs) Fail(args ...interface{}) (string, error) {
return "", errors.Errorf("wrong number of args: want 0 or 1, got %d", len(args))
}
}

// Required -
func (f *TestFuncs) Required(args ...interface{}) (interface{}, error) {
switch len(args) {
case 1:
return test.Required("", args[0])
case 2:
message, ok := args[0].(string)
if !ok {
return nil, errors.Errorf("at <1>: expected string; found %T", args[0])
}
return test.Required(message, args[1])
default:
return "", errors.Errorf("wrong number of args: want 1 or 2, got %d", len(args))
}
}
13 changes: 13 additions & 0 deletions test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package test

import (
"github.com/pkg/errors"
"reflect"
)

// Assert -
Expand All @@ -22,3 +23,15 @@ func Fail(message string) error {
}
return errors.New("template generation failed")
}

// Required -
func Required(message string, value interface{}) (interface{}, error) {
if message == "" {
message = "can not render template: a required value not was not set"
}

if value == nil || reflect.DeepEqual(value, reflect.Zero(reflect.TypeOf(value)).Interface()) {
return nil, errors.New(message)
}
return value, nil
}

0 comments on commit 4f655be

Please sign in to comment.