diff --git a/lib/travis/yml/parts/part.rb b/lib/travis/yml/parts/part.rb index 7c1287a5b..92b561614 100644 --- a/lib/travis/yml/parts/part.rb +++ b/lib/travis/yml/parts/part.rb @@ -9,6 +9,7 @@ class Part deep_merge deep_merge_append deep_merge_prepend + deep_merge_patch replace ) diff --git a/lib/travis/yml/support/merge.rb b/lib/travis/yml/support/merge.rb index 933b9da54..111190674 100644 --- a/lib/travis/yml/support/merge.rb +++ b/lib/travis/yml/support/merge.rb @@ -66,6 +66,21 @@ def deep_merge_prepend(lft, rgt) end end + def deep_merge_patch(lft, rgt) + keys(lft, rgt).inject(lft) do |hash, key| + hash[key] = if hashes?(lft[key], rgt[key]) + send(mode(lft[key]) || :deep_merge_patch, lft[key], rgt[key]) + elsif arrays?(lft[key], rgt[key]) + send(mode(lft[key]) || :patch, lft[key], rgt[key]) + elsif lft.key?(key) + lft[key] + else + rgt[key] + end + hash + end + end + def prepend(lft, rgt) lft.replace(rgt + lft) end @@ -74,6 +89,17 @@ def append(lft, rgt) lft.replace(lft + rgt) end + def patch(lft, rgt) + lft.each.with_index do |_, ix| + rgt[ix] = if hashes?(rgt[ix], lft[ix]) + deep_merge_patch(lft[ix], rgt[ix]) + else + lft[ix] || rgt[ix] + end + end + rgt + end + def mode(obj) obj.merge_mode if obj.respond_to?(:merge_mode) end diff --git a/spec/travis/yml/support/merge_spec.rb b/spec/travis/yml/support/merge_spec.rb index e113ce4cd..b08d31058 100644 --- a/spec/travis/yml/support/merge_spec.rb +++ b/spec/travis/yml/support/merge_spec.rb @@ -57,6 +57,38 @@ it { expect(subject.keys.first.line).to eq 2 } end + describe 'deep_merge_append' do + let(:mode) { :deep_merge_append } + it { should eq 'foo' => { 'one' => ['one', 'two'], 'two' => 'two' }, 'bar' => 'bar' } + it { expect(subject.keys.first).to be_a Key } + it { expect(subject.keys.first.line).to eq 2 } + end + + describe 'deep_merge_patch' do + let(:mode) { :deep_merge_patch } + + let(:lft) do + parse %( + foo: + bar: + - one: two + - + - three: three + ) + end + + let(:rgt) do + parse %( + foo: + bar: + - one: one + - two: two + ) + end + + it { should eq 'foo' => { 'bar' => [{ 'one' => 'two' }, { 'two' => 'two' }, { 'three' => 'three'}] } } + end + describe 'merge tags (1)' do let(:lft) do parse %(