diff --git a/commands_test.go b/commands_test.go index 9c2bfdf..45c23c5 100644 --- a/commands_test.go +++ b/commands_test.go @@ -612,14 +612,46 @@ func TestMergeOverwriteCmd(t *testing.T) { } expectedOutput := `a: other b: -- 1 -- 2 +- 3 +- 4 c: test: 1 ` assertResult(t, expectedOutput, result.Output) } +func TestMergeAppendCmd(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "merge --append examples/data1.yaml examples/data2.yaml") + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := `a: simple +b: +- 1 +- 2 +- 3 +- 4 +c: + test: 1 +` + assertResult(t, expectedOutput, result.Output) +} +func TestMergeArraysCmd(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "merge --append examples/sample_array.yaml examples/sample_array_2.yaml") + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := `- 1 +- 2 +- 3 +- 4 +- 5 +` + assertResult(t, expectedOutput, result.Output) +} + func TestMergeCmd_Multi(t *testing.T) { cmd := getRootCommand() result := runCmd(cmd, "merge -d1 examples/multiple_docs_small.yaml examples/data2.yaml") @@ -631,6 +663,9 @@ func TestMergeCmd_Multi(t *testing.T) { a: other another: document: here +b: +- 3 +- 4 c: test: 1 --- diff --git a/examples/data2.yaml b/examples/data2.yaml index a4312f1..9c51b1f 100644 --- a/examples/data2.yaml +++ b/examples/data2.yaml @@ -1,3 +1,4 @@ a: other +b: [3, 4] c: test: 1 diff --git a/examples/sample_array_2.yaml b/examples/sample_array_2.yaml new file mode 100644 index 0000000..b32037f --- /dev/null +++ b/examples/sample_array_2.yaml @@ -0,0 +1 @@ +[4,5] \ No newline at end of file diff --git a/merge.go b/merge.go index 68cbb5f..863bd0a 100644 --- a/merge.go +++ b/merge.go @@ -2,9 +2,11 @@ package main import "gopkg.in/imdario/mergo.v0" -func merge(dst, src interface{}, overwrite bool) error { +func merge(dst interface{}, src interface{}, overwrite bool, append bool) error { if overwrite { - return mergo.MergeWithOverwrite(dst, src) + return mergo.Merge(dst, src, mergo.WithOverride) + } else if append { + return mergo.Merge(dst, src, mergo.WithAppendSlice) } return mergo.Merge(dst, src) } diff --git a/version.go b/version.go index f210af3..4446921 100644 --- a/version.go +++ b/version.go @@ -11,7 +11,7 @@ var ( GitDescribe string // Version is main version number that is being run at the moment. - Version = "2.0.1" + Version = "2.1.0" // VersionPrerelease is a pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release diff --git a/yq.go b/yq.go index 60d40a8..d431b9b 100644 --- a/yq.go +++ b/yq.go @@ -22,6 +22,7 @@ var writeInplace = false var writeScript = "" var outputToJSON = false var overwriteFlag = false +var appendFlag = false var verbose = false var version = false var docIndex = "0" @@ -183,23 +184,28 @@ func createMergeCmd() *cobra.Command { var cmdMerge = &cobra.Command{ Use: "merge [initial_yaml_file] [additional_yaml_file]...", Aliases: []string{"m"}, - Short: "yq m [--inplace/-i] [--doc/-d index] [--overwrite/-x] sample.yaml sample2.yaml", + Short: "yq m [--inplace/-i] [--doc/-d index] [--overwrite/-x] [--append/-a] sample.yaml sample2.yaml", Example: ` yq merge things.yaml other.yaml yq merge --inplace things.yaml other.yaml yq m -i things.yaml other.yaml yq m --overwrite things.yaml other.yaml yq m -i -x things.yaml other.yaml +yq m -i -a things.yaml other.yaml `, Long: `Updates the yaml file by adding/updating the path(s) and value(s) from additional yaml file(s). Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead. If overwrite flag is set then existing values will be overwritten using the values from each additional yaml file. +If append flag is set then existing arrays will be merged with the arrays from each additional yaml file. + +Note that if you set both flags only overwrite will take effect. `, RunE: mergeProperties, } cmdMerge.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace") cmdMerge.PersistentFlags().BoolVarP(&overwriteFlag, "overwrite", "x", false, "update the yaml file by overwriting existing values") + cmdMerge.PersistentFlags().BoolVarP(&appendFlag, "append", "a", false, "update the yaml file by appending array values") cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)") return cmdMerge } @@ -420,7 +426,11 @@ func mergeProperties(cmd *cobra.Command, args []string) error { if updateAll || currentIndex == docIndexInt { log.Debugf("Merging doc %v", currentIndex) var mergedData map[interface{}]interface{} - if err := merge(&mergedData, dataBucket, overwriteFlag); err != nil { + // merge only works for maps, so put everything in a temporary + // map + var mapDataBucket = make(map[interface{}]interface{}) + mapDataBucket["root"] = dataBucket + if err := merge(&mergedData, mapDataBucket, overwriteFlag, appendFlag); err != nil { return nil, err } for _, f := range filesToMerge { @@ -428,11 +438,12 @@ func mergeProperties(cmd *cobra.Command, args []string) error { if err := readData(f, 0, &fileToMerge); err != nil { return nil, err } - if err := merge(&mergedData, fileToMerge, overwriteFlag); err != nil { + mapDataBucket["root"] = fileToMerge + if err := merge(&mergedData, mapDataBucket, overwriteFlag, appendFlag); err != nil { return nil, err } } - return mergedData, nil + return mergedData["root"], nil } return dataBucket, nil }