Implement new pipeline retry service
The new service takes stages order into account.
This commit is contained in:
parent
19ef4083f3
commit
c65e96061b
|
@ -19,6 +19,10 @@ module Ci
|
||||||
name
|
name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def index
|
||||||
|
statuses.first.stage_idx
|
||||||
|
end
|
||||||
|
|
||||||
def statuses_count
|
def statuses_count
|
||||||
@statuses_count ||= statuses.count
|
@statuses_count ||= statuses.count
|
||||||
end
|
end
|
||||||
|
@ -45,6 +49,14 @@ module Ci
|
||||||
status.to_s == 'success'
|
status.to_s == 'success'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def failed?
|
||||||
|
status.to_s == 'failed'
|
||||||
|
end
|
||||||
|
|
||||||
|
def canceled?
|
||||||
|
status.to_s == 'canceled'
|
||||||
|
end
|
||||||
|
|
||||||
def has_warnings?
|
def has_warnings?
|
||||||
if @warnings.nil?
|
if @warnings.nil?
|
||||||
statuses.latest.failed_but_allowed.any?
|
statuses.latest.failed_but_allowed.any?
|
||||||
|
|
|
@ -9,11 +9,7 @@ module Ci
|
||||||
end
|
end
|
||||||
|
|
||||||
def retry!
|
def retry!
|
||||||
unless can?(@user, :update_build, @build)
|
reprocess!.tap do |new_build|
|
||||||
raise Gitlab::Access::AccessDeniedError
|
|
||||||
end
|
|
||||||
|
|
||||||
clone_build.tap do |new_build|
|
|
||||||
new_build.enqueue!
|
new_build.enqueue!
|
||||||
|
|
||||||
MergeRequests::AddTodoWhenBuildFailsService
|
MergeRequests::AddTodoWhenBuildFailsService
|
||||||
|
@ -24,9 +20,11 @@ module Ci
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def reprocess!
|
||||||
|
unless can?(@user, :update_build, @build)
|
||||||
|
raise Gitlab::Access::AccessDeniedError
|
||||||
|
end
|
||||||
|
|
||||||
def clone_build
|
|
||||||
Ci::Build.create(
|
Ci::Build.create(
|
||||||
ref: @build.ref,
|
ref: @build.ref,
|
||||||
tag: @build.tag,
|
tag: @build.tag,
|
||||||
|
|
|
@ -12,10 +12,31 @@ module Ci
|
||||||
raise Gitlab::Access::AccessDeniedError
|
raise Gitlab::Access::AccessDeniedError
|
||||||
end
|
end
|
||||||
|
|
||||||
@pipeline.stages.each do |stage|
|
##
|
||||||
stage.builds.failed_or_canceled.find_each do |build|
|
# Reprocess builds in subsequent stages if any
|
||||||
Ci::Build.retry(build, @user)
|
#
|
||||||
|
# TODO, refactor.
|
||||||
|
#
|
||||||
|
@pipeline.builds
|
||||||
|
.where('stage_idx > ?', resume_stage.index)
|
||||||
|
.failed_or_canceled.find_each do |build|
|
||||||
|
Ci::RetryBuildService.new(build, @user).reprocess!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Retry builds in the first unsuccessful stage
|
||||||
|
#
|
||||||
|
resume_stage.builds.failed_or_canceled.find_each do |build|
|
||||||
|
Ci::Build.retry(build, @user)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def resume_stage
|
||||||
|
@resume_stage ||= @pipeline.stages.find do |stage|
|
||||||
|
stage.failed? || stage.canceled?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,6 +21,51 @@ describe Ci::RetryPipelineService, '#execute', :services do
|
||||||
|
|
||||||
expect(build('rspec 2')).to be_pending
|
expect(build('rspec 2')).to be_pending
|
||||||
expect(build('rspec 3')).to be_pending
|
expect(build('rspec 3')).to be_pending
|
||||||
|
expect(pipeline.reload).to be_running
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there are failed or canceled builds in the first stage' do
|
||||||
|
before do
|
||||||
|
create_build(name: 'rspec 1', status: :failed, stage_num: 0)
|
||||||
|
create_build(name: 'rspec 2', status: :canceled, stage_num: 0)
|
||||||
|
create_build(name: 'rspec 3', status: :skipped, stage_num: 1)
|
||||||
|
create_build(name: 'deploy 1', status: :skipped, stage_num: 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'retries builds failed builds and marks subsequent for processing' do
|
||||||
|
service.execute
|
||||||
|
|
||||||
|
expect(build('rspec 1')).to be_pending
|
||||||
|
expect(build('rspec 2')).to be_pending
|
||||||
|
expect(build('rspec 3')).to be_created
|
||||||
|
expect(build('deploy 1')).to be_created
|
||||||
|
expect(pipeline.reload).to be_running
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there is failed build present which was run on failure' do
|
||||||
|
before do
|
||||||
|
create_build(name: 'rspec 1', status: :failed, stage_num: 0)
|
||||||
|
create_build(name: 'rspec 2', status: :canceled, stage_num: 0)
|
||||||
|
create_build(name: 'rspec 3', status: :skipped, stage_num: 1)
|
||||||
|
create_build(name: 'report 1', status: :failed, stage_num: 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'retries builds failed builds and marks subsequent for processing' do
|
||||||
|
service.execute
|
||||||
|
|
||||||
|
expect(build('rspec 1')).to be_pending
|
||||||
|
expect(build('rspec 2')).to be_pending
|
||||||
|
expect(build('rspec 3')).to be_created
|
||||||
|
expect(build('report 1')).to be_created
|
||||||
|
expect(pipeline.reload).to be_running
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a new job for report job in this case' do
|
||||||
|
service.execute
|
||||||
|
|
||||||
|
expect(statuses.where(name: 'report 1').count).to eq 2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -32,8 +77,12 @@ describe Ci::RetryPipelineService, '#execute', :services do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def statuses
|
||||||
|
pipeline.reload.statuses
|
||||||
|
end
|
||||||
|
|
||||||
def build(name)
|
def build(name)
|
||||||
pipeline.statuses.find_by(name: name)
|
statuses.latest.find_by(name: name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_build(name:, status:, stage_num:)
|
def create_build(name:, status:, stage_num:)
|
||||||
|
|
Loading…
Reference in New Issue