Feature - Add env variable support for alpha struct (#2375)

* added envsubstring package and added simple test cases.imple tests.

* added documentation

* added changelog entry

* added documentation to wrong file


.

* changed tests to ginkgo format

* update project to use better maintained library

* use defer to clear test variable after tests finished

* updated docs for the new package documentation and fixed bad english

* refactored function to "reduce" complexity.

* updated changelog for new version

updated readme

* minor formatting

---------

Co-authored-by: Haydn Evans <h.evans@douglas.de>
Co-authored-by: Joel Speed <Joel.speed@hotmail.co.uk>
This commit is contained in:
Jan Larwig
2024-01-20 19:37:24 +00:00
committed by GitHub
co-authored by Haydn Evans Joel Speed
parent ee3e9b8841
commit 2f3c811e6a
7 changed files with 80 additions and 14 deletions
+26 -13
View File
@@ -7,6 +7,7 @@ import (
"reflect"
"strings"
"github.com/a8m/envsubst"
"github.com/ghodss/yaml"
"github.com/mitchellh/mapstructure"
"github.com/spf13/pflag"
@@ -140,25 +141,37 @@ func isUnexported(name string) bool {
// LoadYAML will load a YAML based configuration file into the options interface provided.
func LoadYAML(configFileName string, into interface{}) error {
v := viper.New()
v.SetConfigFile(configFileName)
v.SetConfigType("yaml")
v.SetTypeByDefaultValue(true)
if configFileName == "" {
return errors.New("no configuration file provided")
}
data, err := os.ReadFile(configFileName)
buffer, err := loadAndParseYaml(configFileName)
if err != nil {
return fmt.Errorf("unable to load config file: %w", err)
return err
}
// UnmarshalStrict will return an error if the config includes options that are
// not mapped to felds of the into struct
if err := yaml.UnmarshalStrict(data, into, yaml.DisallowUnknownFields); err != nil {
// not mapped to fields of the into struct
if err := yaml.UnmarshalStrict(buffer, into, yaml.DisallowUnknownFields); err != nil {
return fmt.Errorf("error unmarshalling config: %w", err)
}
return nil
}
// Performs the heavy lifting of the LoadYaml function
func loadAndParseYaml(configFileName string) ([]byte, error) {
if configFileName == "" {
return nil, errors.New("no configuration file provided")
}
unparsedBuffer, err := os.ReadFile(configFileName)
if err != nil {
return nil, fmt.Errorf("unable to load config file: %w", err)
}
// We now parse over the yaml with env substring, and fill in the ENV's
buffer, err := envsubst.Bytes(unparsedBuffer)
if err != nil {
return nil, fmt.Errorf("error in substituting env variables : %w", err)
}
return buffer, nil
}
+22 -1
View File
@@ -386,8 +386,13 @@ sub:
DescribeTable("LoadYAML",
func(in loadYAMLTableInput) {
var configFileName string
// Set the required environment variables before running the test
os.Setenv("TESTUSER", "Alice")
// Unset the environment variables after running the test
defer os.Unsetenv("TESTUSER")
var configFileName string
if in.configFile != nil {
By("Creating a config file")
configFile, err := os.CreateTemp("", "oauth2-proxy-test-config-file")
@@ -407,12 +412,14 @@ sub:
} else {
input = &TestOptions{}
}
err := LoadYAML(configFileName, input)
if in.expectedErr != nil {
Expect(err).To(MatchError(in.expectedErr.Error()))
} else {
Expect(err).ToNot(HaveOccurred())
}
Expect(input).To(Equal(in.expectedOutput))
},
Entry("with a valid input", loadYAMLTableInput{
@@ -466,6 +473,20 @@ sub:
expectedOutput: &TestOptions{},
expectedErr: errors.New("error unmarshalling config: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go struct field TestOptions.StringSliceOption of type []string"),
}),
Entry("with a config file containing environment variable references", loadYAMLTableInput{
configFile: []byte("stringOption: ${TESTUSER}"),
input: &TestOptions{},
expectedOutput: &TestOptions{
StringOption: "Alice",
},
}),
Entry("with a config file containing env variable references, with a fallback value", loadYAMLTableInput{
configFile: []byte("stringOption: ${TESTUSER2=Bob}"),
input: &TestOptions{},
expectedOutput: &TestOptions{
StringOption: "Bob",
},
}),
)
})