Kludge used to override default job:only:[branches, tags] in rules-based Job config
Problem
We currently use a little bit of a hack to override default Entry::Policy
values for job:only
and job:except
in the CI configuration.
Gitlab::Ci::Config::Entry::Policy
has a DEFAULT_ONLY = { refs: %w[branches tags] }.freeze
constant that is set as the default value for only:
at the class level in Entry::Job
.
entry :only, Entry::Policy,
description: 'Refs policy this job will be executed for.',
default: Entry::Policy::DEFAULT_ONLY
When using Job rules, we need to optionally override this default at the instance level, because we don't know when this entry
is defined whether or not we will have job rules. And to make the default optionally not be set at the instance level, we would need to add logic about neighboring Entry::Rules
sections into Entry::Policy
, which is a violation of good encapsulation.
To truly fix this would require a nontrivial refactor of how default values are set for Entry objects.
In the mean time, this is our implementation of Entry::Job#compose!
.
def compose!(deps = nil)
super do
if type_defined? && !stage_defined?
@entries[:stage] = @entries[:type]
end
@entries.delete(:type)
# This is something of a hack, see issue for details:
# https://gitlab.com/gitlab-org/gitlab/-/issues/31685
if !only_defined? && has_rules?
@entries.delete(:only)
@entries.delete(:except)
end
end
end
Update:
This also affects workflow:rules
. The following configuration should create a single merge request pipeline, but instead will create nothing:
workflow:
rules:
- if: $CI_MERGE_REQUEST_ID
rspec:
script: echo Hello World
The workflow:rules
specifies that this should only run as a merge request pipeline, but the default only:[branches,tags]
excludes the single job, so no pipeline will be created.
Proposals
Short-term (read: "bad")
We can add another logical possibility to the kludge: check to see if workflow is using rules and delete the default entry of job:only
.
- if !only_defined? && has_rules?
+ if !only_defined? && (has_rules? || workflow_has_rules?)
Better? Less Bad? But also relies on hypothetical pseudocode.
Override Entry::Node#default=
on Entry::Policy. Since the defaults are passed into individual instances of Entry::Node in Entry::Factory:
def fabricate(entry_class, value = nil)
entry_class.new(value, @metadata) do |node|
...
node.default = @attributes[:default]
...
We can define a setter on Entry::Policy to prevent setting the default if there are workflow rules that apply to this pipeline:
def default=(value)
return if workflow_rules? # workflow_used? is completely made up. I don't know how to check for workflow config from an Entry::Node.
@default = value
end