Skip to content

Commit ca9a418

Browse files
authored
ConfigV2: Replace list params - fix #108 (#113)
* Fix #108: Version 2 configs override list params * Version compare must be equals or greater
1 parent 5f018b5 commit ca9a418

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

config/config.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ var (
5656
confidentialValueDecoder(),
5757
))
5858

59+
configOptionV2 = viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
60+
mapstructure.StringToTimeDurationHookFunc(),
61+
confidentialValueDecoder(),
62+
forceSliceReplacementHookFunc(),
63+
))
64+
5965
configOptionHCL = viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
6066
mapstructure.StringToTimeDurationHookFunc(),
6167
confidentialValueDecoder(),
@@ -585,10 +591,28 @@ func (c *Config) getSchedule(key string) (Schedule, error) {
585591
func (c *Config) unmarshalKey(key string, rawVal interface{}) error {
586592
if c.format == "hcl" {
587593
return c.viper.UnmarshalKey(key, rawVal, configOptionHCL)
594+
} else if c.GetVersion() >= Version02 {
595+
return c.viper.UnmarshalKey(key, rawVal, configOptionV2)
588596
}
589597
return c.viper.UnmarshalKey(key, rawVal, configOption)
590598
}
591599

600+
// forceSliceReplacementHookFunc clears the target slice before assigning a new value
601+
func forceSliceReplacementHookFunc() mapstructure.DecodeHookFuncValue {
602+
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
603+
if kind := from.Type().Kind(); (kind == reflect.Slice || kind == reflect.Array || kind == reflect.String) && from.Len() > 0 {
604+
if kind = to.Type().Kind(); (kind == reflect.Slice || kind == reflect.Array) && to.Len() > 0 {
605+
if kind == reflect.Slice {
606+
to.SetLen(0)
607+
} else {
608+
to.Set(to.Slice(0, 0))
609+
}
610+
}
611+
}
612+
return from.Interface(), nil
613+
}
614+
}
615+
592616
// sliceOfMapsToMapHookFunc merges a slice of maps to a map
593617
func sliceOfMapsToMapHookFunc() mapstructure.DecodeHookFunc {
594618
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {

config/config_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,41 @@ profile:
444444

445445
assert.Equal(t, []string{"daily"}, schedules[0].Schedules())
446446
}
447+
448+
func TestRegressionInheritanceListMerging(t *testing.T) {
449+
load := func(content string) *Config {
450+
buffer := bytes.NewBufferString(content)
451+
cfg, err := Load(buffer, FormatYAML)
452+
require.NoError(t, err)
453+
require.NotNil(t, cfg)
454+
return cfg
455+
}
456+
457+
t.Run("Version1", func(t *testing.T) {
458+
config := load(`---
459+
base:
460+
run-before: ["base-first", "base-second", "base-third"]
461+
profile:
462+
inherit: base
463+
run-before: [null, "profile-before"]
464+
`)
465+
profile, err := config.GetProfile("profile")
466+
require.NoError(t, err)
467+
assert.Equal(t, []string{"base-first", "profile-before", "base-third"}, profile.RunBefore)
468+
})
469+
470+
t.Run("Version2", func(t *testing.T) {
471+
config := load(`---
472+
version: 2
473+
profiles:
474+
base:
475+
run-before: ["base-first", "base-second", "base-third"]
476+
profile:
477+
inherit: base
478+
run-before: [null, "profile-before"]
479+
`)
480+
profile, err := config.GetProfile("profile")
481+
require.NoError(t, err)
482+
assert.Equal(t, []string{"", "profile-before"}, profile.RunBefore)
483+
})
484+
}

0 commit comments

Comments
 (0)