Skip to content

Commit 421c4b3

Browse files
Add support for required.
1 parent 80a2b1d commit 421c4b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2609
-2682
lines changed

.goreleaser.yml

+8-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@ builds:
1616
ldflags:
1717
- -s -w -X main.version={{.Version}} -extldflags "-static"
1818
archives:
19-
- replacements:
20-
386: i386
21-
amd64: x86_64
19+
- id: foo
20+
name_template: >-
21+
{{- .ProjectName }}_
22+
{{- .Os }}_
23+
{{- if eq .Arch "amd64" }}x86_64
24+
{{- else if eq .Arch "386" }}i386
25+
{{- else }}{{ .Arch }}{{ end }}
26+
{{- if .Arm }}v{{ .Arm }}{{ end -}}
2227
checksum:
2328
name_template: 'checksums.txt'
2429
snapshot:

README.md

+32-97
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
[![Downloads](https://img.shields.io/github/downloads/patrickdappollonio/tgen/total?color=blue&logo=github&style=flat-square)](https://github.com/patrickdappollonio/tgen/releases)
44

5-
65
`tgen` is a simple CLI application that allows you to write a template file and then use the power of Go Templates to generate an output (which is) outputted to `stdout`. Besides the Go Template engine itself, `tgen` contains a few extra utility functions to assist you when writing templates. See below for a description of each.
76

87
You can also use the `--help` (or `-h`) to see the available set of options. The only flag required is the file to process, and everything else is optional.
@@ -15,7 +14,7 @@ Usage:
1514
1615
Flags:
1716
-e, --environment string an optional environment file to use (key=value formatted) to perform replacements
18-
-f, --file string the template file to process
17+
-f, --file string the template file to process, or "-" to read from stdin
1918
-d, --delimiter string template delimiter (default "{{}}")
2019
-x, --execute string a raw template to execute directly, without providing --file
2120
-v, --values string a file containing values to use for the template, a la Helm
@@ -25,132 +24,68 @@ Flags:
2524
--version version for tgen
2625
```
2726

28-
### Environment file
27+
## Usage
2928

30-
`tgen` supports an optional environment variable collection in a file but it's a pretty basic implementation of a simple key/value pair. The environment file works by finding lines that aren't empty or preceded by a pound `#` -- since they're treated as comments -- and then tries to find at least one equal (`=`) sign. If it can find at least one, all values on the left side of the equal sign become the key and the contents on the right side become the value. If the same line has more than one equal, only the first one is honored and all remaining ones become part of the value.
29+
You can use `tgen`:
3130

32-
There's no support for Bash interpolation or multiline values. If this is needed, consider using a YAML values file instead.
31+
* By reading environment variables from the environment or a key-value file
32+
* By reading variables from a YAML values file
3333

34-
#### Example
34+
While working with it, `tgen` supports a "strict" mode, where if a variable (either environment or from a values file) is used in the template but not set, it will fail the template generation.
3535

36-
Consider the following template, named `template.txt`:
36+
## Examples
3737

38-
```handlebars
39-
The dog licked the {{ env "element" }} and everyone laughed.
40-
```
38+
### Simple template
4139

42-
And the following environment file, named `contents.env`:
40+
Using a template file and an environment file, you can generate a template as follows:
4341

4442
```bash
45-
element=Oil
46-
```
43+
$ cat template.txt
44+
The dog licked the {{ env "element" }} and everyone laughed.
4745

48-
After being passed to `tgen`, the output becomes:
46+
$ cat contents.env
47+
element=Oil
4948

50-
```bash
5149
$ tgen -e contents.env -f template.txt
5250
The dog licked the Oil and everyone laughed.
5351
```
5452

55-
Using the inline mode to execute a template, you can also call the program as such (note the use of single-quotes since in Go, strings are always double-quoted) which will yield the same result:
56-
57-
```bash
58-
$ tgen -x '{{ env "element" }}' -e contents.env
59-
The dog licked the Oil and everyone laughed.
60-
```
61-
62-
Do note as well that using single quotes for the template allows you to prevent any bash special parsing logic that your terminal might have.
63-
64-
### Helm-style values
65-
66-
`tgen` can be used to generate templates, in a very similar way as `helm` can be used. However, do note that `tgen`'s intention is not to replace `helm` since it can't handle application lifecycle the way `helm` does, however, it can do a great job generating resources with very similar code.
67-
68-
Consider the following example of creating a Kubernetes secret for a `tls.crt` file -- in real environments, you'll also need the key, but for the sake of this example, it has been omitted.
69-
70-
Checking the files in the folder:
71-
72-
```bash
73-
tree .
74-
```
75-
76-
```text
77-
.
78-
├── secret.yaml
79-
└── tls.crt
80-
81-
0 directories, 2 files
82-
```
53+
### Inline mode
8354

84-
We have a `secret.yaml` which includes `tgen` templating notation:
55+
You can skip the template file altogether and use the inline mode to execute a template directly:
8556

8657
```bash
87-
cat secret.yaml
88-
```
58+
$ cat contents.env
59+
element=Oil
8960

90-
```yaml
91-
apiVersion: v1
92-
kind: Secret
93-
metadata:
94-
name: secret-tls
95-
type: kubernetes.io/tls
96-
data:
97-
tls.crt: | {{ readfile "tls.crt" | b64enc | nindent 4 }}
61+
$ tgen -e contents.env -x 'The dog licked the {{ env "element" }} and everyone laughed.'
62+
The dog licked the Oil and everyone laughed.
9863
```
9964

100-
The last line includes the following logic:
101-
102-
* Reads the `tls.crt` file from the current directory where `tgen` is run
103-
* Takes the contents of the file and converts it to `base64` -- required by Kubernetes secrets
104-
* Then indents with 4 spaces, starting with a new line
65+
### Helm-style values
10566

106-
To generate the output, we can now run `tgen`:
67+
While `tgen` Helm-like support is currently limited to values, it allows for a powerful way to generate templates. Consider the following example:
10768

10869
```bash
109-
tgen -f secret.yaml
110-
```
111-
112-
And the output looks like this:
113-
114-
```yaml
115-
apiVersion: v1
116-
kind: Secret
117-
metadata:
118-
name: secret-tls
119-
type: kubernetes.io/tls
120-
data:
121-
tls.crt: |
122-
Rk9PQkFSQkFaCg==
123-
```
70+
$ cat template.txt
71+
The dog licked the {{ .element }} and everyone laughed.
12472

125-
This output can be then passed to Kubernetes as follows:
73+
$ cat values.yaml
74+
element: Oil
12675

127-
```
128-
tgen -f secret.yaml | kubectl apply -f -
129-
```
130-
131-
Do keep in mind though your DevOps requirements in terms of keeping a copy of your YAML files, rendered. Additionally, the `readfile` function is akin to `helm`'s `.Files`, with the exception that **you can read any file the `tgen` binary has access**, including potentially sensitive files such as `/etc/passwd`. If this is a concern, please run `tgen` in a CI/CD environment or where access to these resources is limited.
132-
133-
You can also use a `values.yaml` file like Helm. `tgen` will allow you to read values from the values file as `.variable` or `.Values.variable`. The latter is the same as Helm's `.Values.variable` and the former is a shortcut to `.Values.variable` for convenience. Consider the following YAML values file:
134-
135-
```yaml
136-
name: Patrick
137-
```
138-
139-
And the following template:
140-
141-
```handlebars
142-
Hello, my name is {{ .name }}.
76+
$ tgen -v values.yaml -f template.txt
77+
The dog licked the Oil and everyone laughed.
14378
```
14479

145-
Running `tgen` with the values file will yield the following output:
80+
In the last function call, if your file is named `values.yaml`, you can omit it calling it directly and instead use:
14681

14782
```bash
148-
$ tgen -f template.yaml -v values.yaml
149-
Hello, my name is Patrick.
83+
$ tgen --with-values -f template.txt
84+
The dog licked the Oil and everyone laughed.
15085
```
15186

152-
If your values file is called `values.yaml`, you also have the handy shortcut of simply specifying `--with-values` and `tgen` will automatically include the values file from the current working directory.
87+
For more details, see the ["Kubernetes and Helm-style values" documentation page](docs/helm-style-values.md).
15388

154-
### Template functions
89+
## Template functions
15590

15691
See [template functions](docs/functions.md) for a list of all the functions available.

command.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ func command(w io.Writer, c conf) error {
1515

1616
// Read template from "-x" or "--execute" flag
1717
if c.stdinTemplateFile != "" {
18-
tg.setTemplate("-", c.stdinTemplateFile)
18+
tg.setTemplate(os.Stdin.Name(), c.stdinTemplateFile)
1919
}
2020

2121
// Read template file (either from "--file" or stdin)
2222
if pathToOpen := c.templateFilePath; pathToOpen != "" {
2323
var err error
2424
switch pathToOpen {
2525
case "-":
26-
err = tg.loadTemplateFile("", os.Stdin)
26+
err = tg.loadTemplateFile(os.Stdin.Name(), os.Stdin)
2727
default:
2828
err = tg.loadTemplatePath(pathToOpen)
2929
}

docs/functions.md

+28-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- [`readfile`, `readlocalfile`](#readfile-readlocalfile)
1414
- [`linebyline`, `lbl`](#linebyline-lbl)
1515
- [`after`, `skip`](#after-skip)
16+
- [`required`](#required)
1617

1718
All examples below have been generated using `-x` -- or `--execute`, which allows passing a template as argument rather than reading a file. In either case, whether the template file -- with `-f` or `--file` -- or the template argument is used, all functions are available.
1819

@@ -91,6 +92,8 @@ Both `env` and `envdefault` are case insensitive -- either `"home"` or `"HOME"`
9192

9293
When `--strict` mode is enabled, if `env` is called with a environment variable name with no value set or set to empty, the application will exit with error. Useful if you must receive a value or fail a CI build, for example.
9394

95+
Consider the following example reading these environment variables:
96+
9497
```bash
9598
$ tgen -x '{{ env "user" }}'
9699
patrick
@@ -99,16 +102,22 @@ $ tgen -x '{{ env "USER" }}'
99102
patrick
100103
```
101104

105+
Then trying to read a nonexistent environment variable with `--strict` mode enabled:
106+
102107
```bash
103-
$ tgen -x '{{ env "foobar" }}' -s
104-
Error: strict mode on: environment variable not found: $FOOBAR
108+
$ tgen -x '{{ env "foobar" }}' --strict
109+
Error: evaluating /dev/stdin:1:3: strict mode on: environment variable not found: $FOOBAR
105110
```
106111

112+
And bypassing strict mode by setting a default value:
113+
107114
```bash
108-
$ tgen -x '{{ envdefault "SQL_HOST" "sql.example.com" }}'
115+
$ tgen -x '{{ envdefault "SQL_HOST" "sql.example.com" }}' --strict
109116
sql.example.com
110117
```
111118

119+
For custom messages, [consider using `required` instead](#required).
120+
112121
### `rndstring`
113122

114123
Generates a random string of a given length:
@@ -199,3 +208,19 @@ $ tgen -x '{{ after 2 (seq 5) }}'
199208
$ tgen -x '{{ seq 5 | after 2 }}'
200209
[3 4 5]
201210
```
211+
212+
### `required`
213+
214+
Returns an error if the value is empty. Useful to ensure a value is provided, and if not, fail the template generation.
215+
216+
```bash
217+
$ tgen -x '{{ env "foo" | required "environment variable \"foo\" is required" }}'
218+
Error: evaluating /dev/stdin:1:15: environment variable "foo" is required
219+
```
220+
221+
Note that you can also use `--strict` mode to achieve a similar result. The difference between `--strict` and `required` is that `required` works anywhere: not just on missing YAML value keys or environment variables. Here's another example:
222+
223+
```bash
224+
$ tgen -x '{{ "" | required "Value must be set" }}'
225+
Error: evaluating /dev/stdin:1:8: Value must be set
226+
```

docs/helm-style-values.md

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Kubernetes & Helm-style values
2+
3+
Consider the following example of creating a Kubernetes secret for a `tls.crt` file -- in real environments, you'll also need the key, but for the sake of this example, it has been omitted.
4+
5+
Checking the files in the folder:
6+
7+
```bash
8+
tree .
9+
```
10+
11+
```text
12+
.
13+
├── secret.yaml
14+
└── tls.crt
15+
16+
0 directories, 2 files
17+
```
18+
19+
We have a `secret.yaml` which includes `tgen` templating notation:
20+
21+
```bash
22+
cat secret.yaml
23+
```
24+
25+
```yaml
26+
apiVersion: v1
27+
kind: Secret
28+
metadata:
29+
name: secret-tls
30+
type: kubernetes.io/tls
31+
data:
32+
tls.crt: | {{ readfile "tls.crt" | b64enc | nindent 4 }}
33+
```
34+
35+
The last line includes the following logic:
36+
37+
* Reads the `tls.crt` file from the current directory where `tgen` is run
38+
* Takes the contents of the file and converts it to `base64` -- required by Kubernetes secrets
39+
* Then indents with 4 spaces, starting with a new line
40+
41+
To generate the output, we can now run `tgen`:
42+
43+
```bash
44+
tgen -f secret.yaml
45+
```
46+
47+
And the output looks like this:
48+
49+
```yaml
50+
apiVersion: v1
51+
kind: Secret
52+
metadata:
53+
name: secret-tls
54+
type: kubernetes.io/tls
55+
data:
56+
tls.crt: |
57+
Rk9PQkFSQkFaCg==
58+
```
59+
60+
This output can be then passed to Kubernetes as follows:
61+
62+
```
63+
tgen -f secret.yaml | kubectl apply -f -
64+
```
65+
66+
Do keep in mind though your DevOps requirements in terms of keeping a copy of your YAML files, rendered. Additionally, the `readfile` function is akin to `helm`'s `.Files`, with the exception that **you can read any file the `tgen` binary has access**, including potentially sensitive files such as `/etc/passwd`. If this is a concern, please run `tgen` in a CI/CD environment or where access to these resources is limited.
67+
68+
You can also use a `values.yaml` file like Helm. `tgen` will allow you to read values from the values file as `.variable` or `.Values.variable`. The latter is the same as Helm's `.Values.variable` and the former is a shortcut to `.Values.variable` for convenience. Consider the following YAML values file:
69+
70+
```yaml
71+
name: Patrick
72+
```
73+
74+
And the following template:
75+
76+
```handlebars
77+
Hello, my name is {{ .name }}.
78+
```
79+
80+
Running `tgen` with the values file will yield the following output:
81+
82+
```bash
83+
$ tgen -f template.yaml -v values.yaml
84+
Hello, my name is Patrick.
85+
```
86+
87+
If your values file is called `values.yaml`, you also have the handy shortcut of simply specifying `--with-values` and `tgen` will automatically include the values file from the current working directory.

0 commit comments

Comments
 (0)