diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 53003152791878c63641437969ed3da5346fd905..f9c7bb45018aaf677febef0c305c914296ca6d7f 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -377,11 +377,15 @@ def self.latest_successful_for_sha(sha) end def self.latest_successful_for_refs(refs) - relation = newest_first(ref: refs).success + return Ci::Pipeline.none if refs.empty? - relation.each_with_object({}) do |pipeline, hash| - hash[pipeline.ref] ||= pipeline - end + refs_values = refs.map { |ref| "(#{connection.quote(ref)})" }.join(",") + join_query = success.where("refs_values.ref = ci_pipelines.ref").order(id: :desc).limit(1) + + Ci::Pipeline + .from("(VALUES #{refs_values}) refs_values (ref)") + .joins("INNER JOIN LATERAL (#{join_query.to_sql}) #{Ci::Pipeline.table_name} ON TRUE") + .index_by(&:ref) end def self.latest_running_for_ref(ref) diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 74a476a642219e14a6b5c2270aabc3befd2c4a68..8ab94301f7e397a20e439adf857cdbb4ddc6b409 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -2263,18 +2263,38 @@ def create_pipeline(status, ref, sha) end describe '.latest_successful_for_refs' do - let!(:latest_successful_pipeline1) do - create_pipeline(:success, 'ref1', 'D') - end + subject(:latest_successful_for_refs) { described_class.latest_successful_for_refs(refs) } + + context 'when refs are specified' do + let(:refs) { %w(first_ref second_ref third_ref) } + + before do + create(:ci_empty_pipeline, id: 1001, status: :success, ref: 'first_ref', sha: 'sha') + create(:ci_empty_pipeline, id: 1002, status: :success, ref: 'second_ref', sha: 'sha') + end - let!(:latest_successful_pipeline2) do - create_pipeline(:success, 'ref2', 'D') + let!(:latest_successful_pipeline_for_first_ref) do + create(:ci_empty_pipeline, id: 2001, status: :success, ref: 'first_ref', sha: 'sha') + end + + let!(:latest_successful_pipeline_for_second_ref) do + create(:ci_empty_pipeline, id: 2002, status: :success, ref: 'second_ref', sha: 'sha') + end + + it 'returns the latest successful pipeline for both refs' do + expect(latest_successful_for_refs).to eq({ + 'first_ref' => latest_successful_pipeline_for_first_ref, + 'second_ref' => latest_successful_pipeline_for_second_ref + }) + end end - it 'returns the latest successful pipeline for both refs' do - refs = %w(ref1 ref2 ref3) + context 'when no refs are specified' do + let(:refs) { [] } - expect(described_class.latest_successful_for_refs(refs)).to eq({ 'ref1' => latest_successful_pipeline1, 'ref2' => latest_successful_pipeline2 }) + it 'returns an empty relation whenno refs are specified' do + expect(latest_successful_for_refs).to be_empty + end end end end