Skip to content

Commit 7a25c17

Browse files
authoredJun 20, 2023
feat!: accept expand as an option to the env tag (#263)
BREAKING CHANGE: this replaces the `envExpand` tag with the `expand` option to the `env` tag, to be more consistent with other boolean options. closes #262 Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
1 parent 390412e commit 7a25c17

File tree

4 files changed

+27
-14
lines changed

4 files changed

+27
-14
lines changed
 

‎README.md

+16-6
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ type config struct {
3434
IsProduction bool `env:"PRODUCTION"`
3535
Hosts []string `env:"HOSTS" envSeparator:":"`
3636
Duration time.Duration `env:"DURATION"`
37-
TempFolder string `env:"TEMP_FOLDER" envDefault:"${HOME}/tmp" envExpand:"true"`
37+
TempFolder string `env:"TEMP_FOLDER,expand" envDefault:"${HOME}/tmp"`
3838
}
3939

4040
func main() {
@@ -102,10 +102,6 @@ case of absence of it in the environment.
102102
By default, slice types will split the environment value on `,`; you can change
103103
this behavior by setting the `envSeparator` tag.
104104

105-
If you set the `envExpand` tag, environment variables (either in `${var}` or
106-
`$var` format) in the string will be replaced according with the actual value
107-
of the variable.
108-
109105
## Custom Parser Funcs
110106

111107
If you have a type that is not supported out of the box by the lib, you are able
@@ -168,6 +164,20 @@ type config struct {
168164
> value.
169165
> This also means that custom parser funcs will not be invoked.
170166
167+
## Expand vars
168+
169+
If you set the `expand` option, environment variables (either in `${var}` or
170+
`$var` format) in the string will be replaced according with the actual value
171+
of the variable. For example:
172+
173+
```go
174+
type config struct {
175+
SecretKey string `env:"SECRET_KEY,expand"`
176+
}
177+
```
178+
179+
This also works with `envDefault`.
180+
171181
## Not Empty fields
172182

173183
While `required` demands the environment variable to be set, it doesn't check
@@ -214,7 +224,7 @@ import (
214224
type config struct {
215225
Secret string `env:"SECRET,file"`
216226
Password string `env:"PASSWORD,file" envDefault:"/tmp/password"`
217-
Certificate string `env:"CERTIFICATE,file" envDefault:"${CERTIFICATE_FILE}" envExpand:"true"`
227+
Certificate string `env:"CERTIFICATE,file,expand" envDefault:"${CERTIFICATE_FILE}"`
218228
}
219229

220230
func main() {

‎env.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ func get(field reflect.StructField, opts Options) (val string, err error) {
252252
var loadFile bool
253253
var unset bool
254254
var notEmpty bool
255+
var expand bool
255256

256257
required := opts.RequiredIfNoDef
257258
ownKey, tags := parseKeyForOption(field.Tag.Get(opts.TagName))
@@ -271,14 +272,15 @@ func get(field reflect.StructField, opts Options) (val string, err error) {
271272
unset = true
272273
case "notEmpty":
273274
notEmpty = true
275+
case "expand":
276+
expand = true
274277
default:
275278
return "", newNoSupportedTagOptionError(tag)
276279
}
277280
}
278281

279282
prefix := opts.Prefix
280283
key := prefix + ownKey
281-
expand := strings.EqualFold(field.Tag.Get("envExpand"), "true")
282284
defaultValue, defExists := field.Tag.Lookup("envDefault")
283285
val, exists, isDefault = getOr(key, defaultValue, defExists, opts.Environment)
284286

‎env_test.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -933,11 +933,11 @@ func TestErrorRequiredNotSetWithDefault(t *testing.T) {
933933
func TestParseExpandOption(t *testing.T) {
934934
type config struct {
935935
Host string `env:"HOST" envDefault:"localhost"`
936-
Port int `env:"PORT" envDefault:"3000" envExpand:"True"`
937-
SecretKey string `env:"SECRET_KEY" envExpand:"True"`
936+
Port int `env:"PORT,expand" envDefault:"3000"`
937+
SecretKey string `env:"SECRET_KEY,expand"`
938938
ExpandKey string `env:"EXPAND_KEY"`
939-
CompoundKey string `env:"HOST_PORT" envDefault:"${HOST}:${PORT}" envExpand:"True"`
940-
Default string `env:"DEFAULT" envDefault:"def1" envExpand:"True"`
939+
CompoundKey string `env:"HOST_PORT,expand" envDefault:"${HOST}:${PORT}"`
940+
Default string `env:"DEFAULT,expand" envDefault:"def1"`
941941
}
942942

943943
t.Setenv("HOST", "localhost")
@@ -1311,6 +1311,7 @@ func ExampleParse() {
13111311
Home string `env:"HOME,required"`
13121312
Port int `env:"PORT" envDefault:"3000"`
13131313
IsProduction bool `env:"PRODUCTION"`
1314+
TempFolder string `env:"TEMP_FOLDER,expand" envDefault:"${HOME}/.tmp"`
13141315
Inner inner
13151316
}
13161317
os.Setenv("HOME", "/tmp/fakehome")
@@ -1319,7 +1320,7 @@ func ExampleParse() {
13191320
fmt.Println("failed:", err)
13201321
}
13211322
fmt.Printf("%+v", cfg)
1322-
// Output: {Home:/tmp/fakehome Port:3000 IsProduction:false Inner:{Foo:foobar}}
1323+
// Output: {Home:/tmp/fakehome Port:3000 IsProduction:false TempFolder:/tmp/fakehome/.tmp Inner:{Foo:foobar}}
13231324
}
13241325

13251326
func ExampleParse_onSet() {
@@ -1495,7 +1496,7 @@ func TestFileBadFile(t *testing.T) {
14951496

14961497
func TestFileWithDefault(t *testing.T) {
14971498
type config struct {
1498-
SecretKey string `env:"SECRET_KEY,file" envDefault:"${FILE}" envExpand:"true"`
1499+
SecretKey string `env:"SECRET_KEY,file,expand" envDefault:"${FILE}"`
14991500
}
15001501

15011502
dir := t.TempDir()

‎error.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func (e NoParserError) Error() string {
8989
}
9090

9191
// This error occurs when the given tag is not supported
92-
// In-built supported tags: "", "file", "required", "unset", "notEmpty", "envDefault", "envExpand", "envSeparator"
92+
// In-built supported tags: "", "file", "required", "unset", "notEmpty", "expand", "envDefault", "envSeparator"
9393
// How to create a custom tag: https://github.com/caarlos0/env#changing-default-tag-name
9494
type NoSupportedTagOptionError struct {
9595
Tag string

0 commit comments

Comments
 (0)