Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only overwrite values when environment variables are set #62

Merged
merged 1 commit into from
Jul 14, 2022

Conversation

sethvargo
Copy link
Owner

The previous implementation of overwrite would always overwrite values in the given struct, even if values existed. While this is the definition of overwrite, it unintentionally extended to default values as well. So even if a value was explicitly set on a struct, it would be overwritten with the "default" value set in envconfig. This was an unexpected behavior, since defaults should take the lowest precedence.

The new implementation has the following behavior with overwrite:

  • If the struct field has the zero value and a default is set:

    • If no environment variable is specified, the struct field will be populated with the default value.

    • If an environment variable is specified, the struct field will be populate with the environment variable value.

  • If the struct field has a non-zero value and a default is set:

    • If no environment variable is specified, the struct field's existing value will be used (the default is ignored).

    • If an environment variable is specified, the struct field's existing value will be overwritten with the environment variable value.

As part of this change, decoder interfaces are only processed when an environment (or a default) is present.

Closes #61

/cc @raserva @twmb

The previous implementation of `overwrite` would always overwrite values in the given struct, even if values existed. While this is the definition of `overwrite`, it unintentionally extended to `default` values as well. So even if a value was explicitly set on a struct, it would be overwritten with the "default" value set in envconfig. This was an unexpected behavior, since defaults should take the lowest precedence.

The new implementation has the following behavior with `overwrite`:

- If the struct field has the zero value and a default is set:

    - If no environment variable is specified, the struct field will be populated with the default value.

    - If an environment variable is specified, the struct field will be populate with the environment variable value.

- If the struct field has a non-zero value and a default is set:

    - If no environment variable is specified, the struct field's existing value will be used (the default is ignored).

    - If an environment variable is specified, the struct field's existing value will be overwritten with the environment variable value.

As part of this change, decoder interfaces are only processed when an environment (or a default) is present.
@sethvargo sethvargo merged commit 1a03b30 into main Jul 14, 2022
@sethvargo sethvargo deleted the sethvargo/defaults branch July 14, 2022 02:13
@twmb
Copy link

twmb commented Jul 14, 2022

Interesting, thank you for the quick fix!

I've confirmed this fixes the problem I was running into :)

williamgcampbell pushed a commit to williamgcampbell/go-envconfig that referenced this pull request Jul 26, 2022
The previous implementation of `overwrite` would always overwrite values in the given struct, even if values existed. While this is the definition of `overwrite`, it unintentionally extended to `default` values as well. So even if a value was explicitly set on a struct, it would be overwritten with the "default" value set in envconfig. This was an unexpected behavior, since defaults should take the lowest precedence.

The new implementation has the following behavior with `overwrite`:

- If the struct field has the zero value and a default is set:

    - If no environment variable is specified, the struct field will be populated with the default value.

    - If an environment variable is specified, the struct field will be populate with the environment variable value.

- If the struct field has a non-zero value and a default is set:

    - If no environment variable is specified, the struct field's existing value will be used (the default is ignored).

    - If an environment variable is specified, the struct field's existing value will be overwritten with the environment variable value.

As part of this change, decoder interfaces are only processed when an environment (or a default) is present.
sethvargo added a commit that referenced this pull request Jul 27, 2022
This reverts part of #62 to always process decoder interfaces for struct fields. This removes a breaking change where certain built-in types like net/url.URL have a custom unmarshaling function for the empty string.

The other rules for "overwrite" still apply.
@sethvargo sethvargo mentioned this pull request Jul 27, 2022
sethvargo added a commit that referenced this pull request Jul 27, 2022
This reverts part of #62 to always process decoder interfaces for struct fields. This removes a breaking change where certain built-in types like net/url.URL have a custom unmarshaling function for the empty string.

The other rules for "overwrite" still apply.
sethvargo added a commit that referenced this pull request Dec 27, 2023
**:warning: Breaking!** Envconfig no longer runs decoders on unset values! To restore the old behavior, add the `decodeunset` struct field annotation or pass the `DefaultDecodeUnset` configuration option as `true`.

Prior to this change, envconfig would always call decoding functions, even for unset or empty values. This proved problematic for some libraries like `url` and `zap` which implement `TextUnmarshaller`, but error on the empty string (#61). #62 changed the behavior to only call the decoder if a value was explicitly provided, but that broke users unexpectedly (#64), so the change was reverted.

After much discussion, we decided to keep the existing behavior until the 1.0 release. However, after further reflection, I think we need to support a user-level configurable option. Some fields and structs may still want the decoder to run on empty values.

This PR changes envconfig to only process a field if any of the following are true:

- A value was provided (the value can be set to the empty string, there is a distinction between "unset" and "set to empty")
- A default value was provided
- The `decodeunset` struct field tag is set
- The `DefaultDecodeUnset` configuration option is true
sethvargo added a commit that referenced this pull request Dec 27, 2023
**:warning: Breaking!** Envconfig no longer runs decoders on unset values! To restore the old behavior, add the `decodeunset` struct field annotation or pass the `DefaultDecodeUnset` configuration option as `true`.

Prior to this change, envconfig would always call decoding functions, even for unset or empty values. This proved problematic for some libraries like `url` and `zap` which implement `TextUnmarshaller`, but error on the empty string (#61). #62 changed the behavior to only call the decoder if a value was explicitly provided, but that broke users unexpectedly (#64), so the change was reverted.

After much discussion, we decided to keep the existing behavior until the 1.0 release. However, after further reflection, I think we need to support a user-level configurable option. Some fields and structs may still want the decoder to run on empty values.

This PR changes envconfig to only process a field if any of the following are true:

- A value was provided (the value can be set to the empty string, there is a distinction between "unset" and "set to empty")
- A default value was provided
- The `decodeunset` struct field tag is set
- The `DefaultDecodeUnset` configuration option is true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

unset env-vars does not play nicely with custom decode functions
2 participants