In GitLab CI, you can use the extends keyword in order to inherit properties from another job or template.
One example is:
.tests:
script: rake test
stage: test
only:
refs:
- branches
rspec:
extends: .tests
script: rake rspec
only:
variables:
- $RSPEC
Which results in:
rspec:
script: rake rspec
stage: test
only:
refs:
- branches
variables:
- $RSPEC
But as you can see, it is not obvious how each property gets merged. Properties like "only" appear to get merged and other properties like script
appear to get overwritten instead.
I'm trying to understand exactly which properties get overwritten and which properties get merged (and how). Is there a complete list?
Something like this maybe?
Property | Behavior when used with extends |
---|---|
script |
Overwritten |
only |
Merged |
except |
Merged |
variables |
Merged |
before_script |
Overwritten |
after_script |
Overwritten |
needs |
Merged |
cache |
Merged (gets converted from map to list of maps) |
artifacts |
Merged (deep) |
services |
? |
when |
? |
rules |
? |
... | ... |
As documented in merge details, hashes (key, value pairs) get merged, but any other value like arrays are overwritten by the extending job. It works simply by using the deep_merge method which is part of the Ruby on Rails framework.
The actual logic, looks like this:
# File activesupport/lib/active_support/core_ext/hash/deep_merge.rb, line 23
def deep_merge!(other_hash, &block)
merge!(other_hash) do |key, this_val, other_val|
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
this_val.deep_merge(other_val, &block)
elsif block_given?
block.call(key, this_val, other_val)
else
other_val
end
end
end
This means it can be important how you write your YAML, as some configurations accept multiple types. For example variables:
may be a hash of keys and values (or hash of keys and hash of configuration options). It can also be an array of hashes. These different options for writing variables:
will merge differently when used with extends:
. The same goes for many other keys, like only:
and except:
.