Commit c65e9606 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Implement new pipeline retry service

The new service takes stages order into account.
parent 19ef4083
......@@ -19,6 +19,10 @@ module Ci
name
end
def index
statuses.first.stage_idx
end
def statuses_count
@statuses_count ||= statuses.count
end
......@@ -45,6 +49,14 @@ module Ci
status.to_s == 'success'
end
def failed?
status.to_s == 'failed'
end
def canceled?
status.to_s == 'canceled'
end
def has_warnings?
if @warnings.nil?
statuses.latest.failed_but_allowed.any?
......
......@@ -9,11 +9,7 @@ module Ci
end
def retry!
unless can?(@user, :update_build, @build)
raise Gitlab::Access::AccessDeniedError
end
clone_build.tap do |new_build|
reprocess!.tap do |new_build|
new_build.enqueue!
MergeRequests::AddTodoWhenBuildFailsService
......@@ -24,9 +20,11 @@ module Ci
end
end
private
def reprocess!
unless can?(@user, :update_build, @build)
raise Gitlab::Access::AccessDeniedError
end
def clone_build
Ci::Build.create(
ref: @build.ref,
tag: @build.tag,
......
......@@ -12,10 +12,31 @@ module Ci
raise Gitlab::Access::AccessDeniedError
end
@pipeline.stages.each do |stage|
stage.builds.failed_or_canceled.find_each do |build|
Ci::Build.retry(build, @user)
##
# Reprocess builds in subsequent stages if any
#
# TODO, refactor.
#
@pipeline.builds
.where('stage_idx > ?', resume_stage.index)
.failed_or_canceled.find_each do |build|
Ci::RetryBuildService.new(build, @user).reprocess!
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
......
......@@ -21,6 +21,51 @@ describe Ci::RetryPipelineService, '#execute', :services do
expect(build('rspec 2')).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
......@@ -32,8 +77,12 @@ describe Ci::RetryPipelineService, '#execute', :services do
end
end
def statuses
pipeline.reload.statuses
end
def build(name)
pipeline.statuses.find_by(name: name)
statuses.latest.find_by(name: name)
end
def create_build(name:, status:, stage_num:)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment