Fix pipeline status transition when retrying only failed manual jobs
What does this MR do and why?
There is a bug when we retry a pipeline where only manual jobs failed/cancelled, we get an error:An error occured while making the request. Status cannot transition via "succeed"
.
This MR is to resolve it.
Bug Description
Bug Screenshot
Bug video
Test project: https://gitlab.com/qt-gith/issue-1522-test/
Steps to reproduce
- Create a project, such as test project, its
.gitlab-ci.yml
file is as follows:
stages:
- prepare
- test
- end
prepare:
stage: prepare
script:
- echo
test:
stage: test
script:
- echo ${V1}
- if [[ ${V1} == "123" ]]; then echo "Success"; else echo "Error"; exit 11; fi
when: manual
allow_failure: true
needs:
- prepare
- Run the pipeline.(Make sure there is a Runner to execute the job before this.)
- You will see
prepare
is ok, andtest
job awaiting configuration. Configure thetest
job withV1 = 456
and run it, the job will fail. - Refresh the pipeline and retry,
An error occured while making the request. Status cannot transition via "succeed"
error message appears.
Bug Reason
Debug update_pipeline in AtomicProcessingService, we can find:
- Failed manual jobs will be set to
:ignored
in@status_set
ofGitlab::Ci::Status::Composite
when retrying a pipeline. According to composite.rb#ignored_status?. - Pipeline status will be set to
:success
when@status_set
ofGitlab::Ci::Status::Composite
contains only:success
,:skipped
,:success_with_warnings
,:ignored
. According to composite.rb#status. - When we retry a pipeline where only manual jobs fail,
@status_set
ofGitlab::Ci::Status::Composite
contains only:success
and:ignored
, pipeline status will be set to:success
, and then will raise state machine error. According to pipeline.rb.
Solution
Check the new state of the pipeline after update_stages!
in AtomicProcessingService#process!.
Return if the status is :success
.
Another example and explanation of the bug
From !98967 (comment 1144718316);
test1:
script: exit 0
test2:
script: exit 1
when: manual
Initial
The pipeline is success
Ci::Pipeline.last.status # => success
test2
Play The pipeline is passed
Ci::Pipeline.last.status # => success
Retry the pipeline
- Status: The pipeline
status
issuccess
;test1
issuccess
,test2
isfailed
but "passed". - Click the "retry" button.
-
Ci::RetryPipelineService
creates a newtest2
job with thecreated
state. - The retry service calls
Ci::ProcessPipelineService
->AtomicProcessingService
. - In
AtomicProcessingService
;update_stages! -> update_processables! -> update_processable!
updates the status oftest2
fromcreated
tosuccess
. - In
update_pipeline!
,@collection.status_of_all
issuccess
. And we try to update the status ofpipeline
tosuccess
, which is alreadysuccess
.
Solution
- I do not think we should have a customized logic like
return if pipeline.success? && @collection.status_of_all == 'success'
. - We may allow the transition from
success
tosuccess
and it solves the problem. But I am not sure🤔
Edited by Furkan Ayhan