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.ymlfile 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
prepareis ok, andtestjob awaiting configuration. Configure thetestjob withV1 = 456and 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
:ignoredin@status_setofGitlab::Ci::Status::Compositewhen retrying a pipeline. According to composite.rb#ignored_status?. - Pipeline status will be set to
:successwhen@status_setofGitlab::Ci::Status::Compositecontains only:success,:skipped,:success_with_warnings,:ignored. According to composite.rb#status. - When we retry a pipeline where only manual jobs fail,
@status_setofGitlab::Ci::Status::Compositecontains only:successand: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
Play test2
The pipeline is passed
Ci::Pipeline.last.status # => success
Retry the pipeline
- Status: The pipeline
statusissuccess;test1issuccess,test2isfailedbut "passed". - Click the "retry" button.
-
Ci::RetryPipelineServicecreates a newtest2job with thecreatedstate. - The retry service calls
Ci::ProcessPipelineService->AtomicProcessingService. - In
AtomicProcessingService;update_stages! -> update_processables! -> update_processable!updates the status oftest2fromcreatedtosuccess. - In
update_pipeline!,@collection.status_of_allissuccess. And we try to update the status ofpipelinetosuccess, 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
successtosuccessand it solves the problem. But I am not sure🤔
Edited by Furkan Ayhan


