Merge pull request #3511 from andriisoldatenko/add-support-env-vars-slices

Added support for configuring array values with environment variables
This commit is contained in:
Milos Gajdos 2023-08-15 14:14:30 +01:00 committed by GitHub
commit 72dc264241
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 4 deletions

View file

@ -166,6 +166,25 @@ func (p *Parser) overwriteFields(v reflect.Value, fullpath string, path []string
return p.overwriteStruct(v, fullpath, path, payload) return p.overwriteStruct(v, fullpath, path, payload)
case reflect.Map: case reflect.Map:
return p.overwriteMap(v, fullpath, path, payload) return p.overwriteMap(v, fullpath, path, payload)
case reflect.Slice:
idx, err := strconv.Atoi(path[0])
if err != nil {
panic("non-numeric index: " + path[0])
}
if idx > v.Len() {
panic("undefined index: " + path[0])
}
// if there is no element or the current slice length
// is the same as the indexed variable create a new element,
// append it and then set it to the passed in env var value.
if v.Len() == 0 || idx == v.Len() {
typ := v.Type().Elem()
elem := reflect.New(typ).Elem()
v.Set(reflect.Append(v, elem))
}
return p.overwriteFields(v.Index(idx), fullpath, path[1:], payload)
case reflect.Interface: case reflect.Interface:
if v.NumMethod() == 0 { if v.NumMethod() == 0 {
if !v.IsNil() { if !v.IsNil() {

View file

@ -8,21 +8,39 @@ import (
) )
type localConfiguration struct { type localConfiguration struct {
Version Version `yaml:"version"` Version Version `yaml:"version"`
Log *Log `yaml:"log"` Log *Log `yaml:"log"`
Notifications []Notif `yaml:"notifications,omitempty"`
} }
type Log struct { type Log struct {
Formatter string `yaml:"formatter,omitempty"` Formatter string `yaml:"formatter,omitempty"`
} }
type Notif struct {
Name string `yaml:"name"`
}
var expectedConfig = localConfiguration{ var expectedConfig = localConfiguration{
Version: "0.1", Version: "0.1",
Log: &Log{ Log: &Log{
Formatter: "json", Formatter: "json",
}, },
Notifications: []Notif{
{Name: "foo"},
{Name: "bar"},
{Name: "car"},
},
} }
const testConfig = `version: "0.1"
log:
formatter: "text"
notifications:
- name: "foo"
- name: "bar"
- name: "car"`
type ParserSuite struct{} type ParserSuite struct{}
var _ = check.Suite(new(ParserSuite)) var _ = check.Suite(new(ParserSuite))
@ -43,17 +61,32 @@ func (suite *ParserSuite) TestParserOverwriteIninitializedPoiner(c *check.C) {
}, },
}) })
err := p.Parse([]byte(`{version: "0.1", log: {formatter: "text"}}`), &config) err := p.Parse([]byte(testConfig), &config)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
c.Assert(config, check.DeepEquals, expectedConfig) c.Assert(config, check.DeepEquals, expectedConfig)
} }
const testConfig2 = `version: "0.1"
log:
formatter: "text"
notifications:
- name: "val1"
- name: "val2"
- name: "car"`
func (suite *ParserSuite) TestParseOverwriteUnininitializedPoiner(c *check.C) { func (suite *ParserSuite) TestParseOverwriteUnininitializedPoiner(c *check.C) {
config := localConfiguration{} config := localConfiguration{}
os.Setenv("REGISTRY_LOG_FORMATTER", "json") os.Setenv("REGISTRY_LOG_FORMATTER", "json")
defer os.Unsetenv("REGISTRY_LOG_FORMATTER") defer os.Unsetenv("REGISTRY_LOG_FORMATTER")
// override only first two notificationsvalues
// in the tetConfig: leave the last value unchanged.
os.Setenv("REGISTRY_NOTIFICATIONS_0_NAME", "foo")
defer os.Unsetenv("REGISTRY_NOTIFICATIONS_0_NAME")
os.Setenv("REGISTRY_NOTIFICATIONS_1_NAME", "bar")
defer os.Unsetenv("REGISTRY_NOTIFICATIONS_1_NAME")
p := NewParser("registry", []VersionedParseInfo{ p := NewParser("registry", []VersionedParseInfo{
{ {
Version: "0.1", Version: "0.1",
@ -64,7 +97,7 @@ func (suite *ParserSuite) TestParseOverwriteUnininitializedPoiner(c *check.C) {
}, },
}) })
err := p.Parse([]byte(`{version: "0.1"}`), &config) err := p.Parse([]byte(testConfig2), &config)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
c.Assert(config, check.DeepEquals, expectedConfig) c.Assert(config, check.DeepEquals, expectedConfig)
} }