Commit 8efa7c6c authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'sh-fix-pipeline-retry-dag' into 'master'

Fix pipeline retry in a CI DAG

Closes #36068

See merge request gitlab-org/gitlab!21296
parents cf7d5e64 968e6ad5
......@@ -812,6 +812,10 @@ module Ci
@persistent_ref ||= PersistentRef.new(pipeline: self)
end
def find_successful_build_ids_by_names(names)
statuses.latest.success.where(name: names).pluck(:id)
end
private
def pipeline_data
......
......@@ -14,6 +14,8 @@ module Ci
has_many :needs, class_name: 'Ci::BuildNeed', foreign_key: :build_id, inverse_of: :build
accepts_nested_attributes_for :needs
scope :preload_needs, -> { preload(:needs) }
end
def schedulable?
......
......@@ -9,13 +9,23 @@ module Ci
raise Gitlab::Access::AccessDeniedError
end
pipeline.retryable_builds.find_each do |build|
needs = Set.new
pipeline.retryable_builds.preload_needs.find_each do |build|
next unless can?(current_user, :update_build, build)
Ci::RetryBuildService.new(project, current_user)
.reprocess!(build)
needs += build.needs.map(&:name)
end
# In a DAG, the dependencies may have already completed. Figure out
# which builds have succeeded and use them to update the pipeline. If we don't
# do this, then builds will be stuck in the created state since their dependencies
# will never run.
completed_build_ids = pipeline.find_successful_build_ids_by_names(needs) if needs.any?
pipeline.builds.latest.skipped.find_each do |skipped|
retry_optimistic_lock(skipped) { |build| build.process }
end
......@@ -26,7 +36,7 @@ module Ci
Ci::ProcessPipelineService
.new(pipeline)
.execute
.execute(completed_build_ids)
end
end
end
---
title: Fix pipeline retry in a CI DAG
merge_request: 21296
author:
type: fixed
......@@ -91,6 +91,25 @@ describe Ci::RetryPipelineService, '#execute' do
end
end
context 'when there is a failed test in a DAG' do
before do
create_build('build', :success, 0)
create_build('build2', :success, 0)
test_build = create_build('test', :failed, 1)
create(:ci_build_need, build: test_build, name: 'build')
create(:ci_build_need, build: test_build, name: 'build2')
end
it 'retries the test' do
service.execute(pipeline)
expect(build('build')).to be_success
expect(build('build2')).to be_success
expect(build('test')).to be_pending
expect(build('test').needs.map(&:name)).to match_array(%w(build build2))
end
end
context 'when the last stage was skipepd' do
before do
create_build('build 1', :success, 0)
......
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