Spike: introduce manual: required/optional/ignored
As discussed
We would like to extract the manual
keyword from when:
test:
manual: required / optional / ignored
-
manual: required
will work as today'swhen: manual & allow_failure: false
. It'll block dependent jobs. -
manual: optional
will work as today'swhen: manual & allow_failure: true & needs
. It'll skip dependent jobs. -
manual: ignored
will work as today'swhen: manual & allow_failure: true & stage
. It'll be just ignored.
Some technical details;
Today, in the consume_status
method of lib/gitlab/ci/status/composite.rb
, we say ignored
for when: manual & allow_failure: true
jobs. We think that maybe we should return required_manual
, optional_manual
, and ignored_manual
and process accordingly.
As mentioned above, an ignored-manual job is ignored, it's like nothing there. So, even if a DAG job needs
a such job, we consider it does not need it at all. A subsequent stage job will also not care about such a job. In the future, if we introduce needs: [{stage: build}]
, then we will still ignore such jobs inside a stage.
Proposal
We may need to make some changes in our status calculations and usage. Currently, we have some custom conditions and places where we consider skipped
as success;
-
lib/gitlab/ci/status/composite.rb
;
def status
return if none?
strong_memoize(:status) do
if @dag && any_skipped_or_ignored?
# The DAG job is skipped if one of the needs does not run at all.
'skipped'
elsif @dag && !only_of?(:success, :failed, :canceled, :skipped, :success_with_warnings)
# DAG is blocked from executing if a dependent is not "complete"
'pending'
elsif only_of?(:skipped, :ignored)
'skipped'
Today, we have these conditions for DAG;
- In previous jobs, if there is an "ignored manual job", then we return
skipped
. And since we do not considerskipped
as a success status for DAG, we skip the DAG job. (We also discuss this in the next itemapp/services/ci/process_build_service.rb
). - In previous jobs, if there is a skipped job, then we return
skipped
. That "skipped job" is probably skipped because there is anotherfailed
previous job. However, we think that if we skip a DAG job for a single previous skipped job, then we should do this for STAGE too. - We haven't discussed the condition
@dag && !only_of?(:success, :failed, :canceled, :skipped, :success_with_warnings)
but we'll also need to unify the behaviors.
-
app/services/ci/process_build_service.rb
;
def valid_statuses_for_build(build)
case build.when
when 'on_success', 'manual', 'delayed'
build.scheduling_type_dag? ? %w[success] : %w[success skipped]
when 'on_failure'
%w[failed]
when 'always'
%w[success failed skipped]
else
[]
end
end
We think that the reason why skipped
is considered as "success" is the manual job statuses. Today, a manual job with the default allow_failure:true
becomes skipped. However, they behave like "ignored" just like in our proposal. Tip: today, we also have ignored
;
# ...
status =
if success_with_warnings?(description)
:success_with_warnings
elsif ignored_status?(description)
:ignored
else
description[@status_key].to_sym
end
# ... this below actually means "ignored manual jobs"
def ignored_status?(status)
@allow_failure_key &&
status[@allow_failure_key] &&
::Ci::HasStatus::EXCLUDE_IGNORED_STATUSES.include?(status[@status_key])
end
So, if we successfully implement a good way with manual: required / optional / ignored
, we will get rid of the DAG condition there and remove skipped
there;
# we may or may not return `ignored` from `lib/gitlab/ci/status/composite.rb`. let's just keep it here for now.
def valid_statuses_for_build(build)
case build.when
when 'on_success', 'manual', 'delayed'
%w[success ignored]
when 'on_failure'
%w[failed]
when 'always'
%w[success failed skipped ignored]
else
[]
end
end
Implementation table
Group | Issue Link |
---|---|
backend | #393129 (closed) |
spike |
|