diff --git a/main.go b/main.go index 3627241..4a5123d 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,6 @@ import ( "fmt" "io/ioutil" "os" - "strings" "github.com/labstack/gommon/log" "github.com/urfave/cli/v2" @@ -70,22 +69,40 @@ func main() { } } -func removeLastLineIfEmpty(s string) string { - lines := strings.Split(s, "\n") - lastLine := strings.TrimSpace(lines[len(lines)-1]) - if lastLine == "" { - lines = lines[:len(lines)-1] +func mergeMaps(dst, src map[string]interface{}) { + for k, v := range src { + if _, ok := dst[k]; !ok { + // key does not exist in dst, just copy from src + dst[k] = v + continue + } + + // key exists in both dst and src, need to merge recursively + dstValue := dst[k] + switch dstValue := dstValue.(type) { + case map[string]interface{}: + srcValue, ok := v.(map[string]interface{}) + if !ok { + // type mismatch, just copy from src + dst[k] = v + continue + } + mergeMaps(dstValue, srcValue) + default: + // type mismatch or dst has scalar value, just copy from src + dst[k] = v + continue + } } - return strings.Join(lines, "\n") } func MergeYAML(filenames ...string) ([]byte, error) { if len(filenames) <= 0 { return nil, errors.New("You must provide at least one filename for reading Values") } - var resultValues map[string]interface{} - for _, filename := range filenames { + resultValues := make(map[string]interface{}) + for _, filename := range filenames { var override map[string]interface{} bs, err := ioutil.ReadFile(filename) if err != nil { @@ -96,19 +113,7 @@ func MergeYAML(filenames ...string) ([]byte, error) { log.Info(err) return nil, fmt.Errorf("failed to unmarshal data from file %q: %w", filename, err) } - - //check if is nil. This will only happen for the first filename - if resultValues == nil { - resultValues = override - } else { - for k, v := range override { - // Check if value is nil before adding to resultValues - if v != nil { - resultValues[k] = v - } - } - } - + mergeMaps(resultValues, override) } bs, err := yaml.Marshal(resultValues) @@ -117,10 +122,5 @@ func MergeYAML(filenames ...string) ([]byte, error) { return nil, err } - if err != nil { - log.Info(err) - return nil, err - } - return bs, nil } diff --git a/merge_test.go b/merge_test.go index 5b5a139..4fd97fc 100644 --- a/merge_test.go +++ b/merge_test.go @@ -8,6 +8,31 @@ import ( "github.com/stretchr/testify/assert" ) +func TestMergeYAML_InvertedMergeOrder(t *testing.T) { + result, err := MergeYAML("tests/test2.yaml", "tests/test1.yaml") + assert.NoError(t, err) + assert.Equal(t, strings.TrimSpace(` +modules: + my_module: + providerAliasRef: my_provider2 + source: github.com/example/module + version: v1.0.0 + my_module2: + providerAliasRef: my_provider2 + source: github.com/example/module + version: v1.6.0 + my_module3: + providerAliasRef: my_provider2 + source: github.com/example/module + version: v1.6.0 +providers: + my_provider: + auth: + ssh_key: ssh:key:2312312 + providerType: github +`), strings.TrimSpace(string(result))) +} + func TestMergeYAML_TwoFiles(t *testing.T) { result, err := MergeYAML("tests/test1.yaml", "tests/test2.yaml") assert.NoError(t, err)