debian-mirror-gitlab/app/finders/merge_requests/oldest_per_commit_finder.rb

65 lines
2.1 KiB
Ruby
Raw Normal View History

2021-03-11 19:13:27 +05:30
# frozen_string_literal: true
module MergeRequests
# OldestPerCommitFinder is used to retrieve the oldest merge requests for
# every given commit, grouped per commit SHA.
#
# This finder is useful when you need to efficiently retrieve the first/oldest
# merge requests for multiple commits, and you want to do so in batches;
# instead of running a query for every commit.
class OldestPerCommitFinder
def initialize(project)
@project = project
end
# Returns a Hash that maps a commit ID to the oldest merge request that
# introduced that commit.
def execute(commits)
2021-04-17 20:07:23 +05:30
mapping = {}
shas = commits.map(&:id)
2021-04-29 21:17:54 +05:30
# To include merge requests by the merge/squash SHA, we don't need to go
# through any diff rows.
2021-04-17 20:07:23 +05:30
#
# We can't squeeze all this into a single query, as the diff based data
# relies on a GROUP BY. On the other hand, retrieving MRs by their merge
# SHAs separately is much easier, and plenty fast.
@project
.merge_requests
.preload_target_project
2021-04-29 21:17:54 +05:30
.by_merge_or_squash_commit_sha(shas)
2021-04-17 20:07:23 +05:30
.each do |mr|
2021-04-29 21:17:54 +05:30
# Merge/squash SHAs can't be in the merge request itself. It _is_
# possible a newer merge request includes the commit, but in that case
# we still want the oldest merge request.
#
# It's also possible that a merge request produces both a squashed
# commit and a merge commit. In that case we want to store the mapping
# for both the SHAs.
mapping[mr.squash_commit_sha] = mr if mr.squash_commit_sha
mapping[mr.merge_commit_sha] = mr if mr.merge_commit_sha
2021-04-17 20:07:23 +05:30
end
remaining = shas - mapping.keys
return mapping if remaining.empty?
2021-03-11 19:13:27 +05:30
id_rows = MergeRequestDiffCommit
2021-04-17 20:07:23 +05:30
.oldest_merge_request_id_per_commit(@project.id, remaining)
2021-03-11 19:13:27 +05:30
mrs = MergeRequest
.preload_target_project
.id_in(id_rows.map { |r| r[:merge_request_id] })
.index_by(&:id)
2021-04-17 20:07:23 +05:30
id_rows.each do |row|
2021-03-11 19:13:27 +05:30
if (mr = mrs[row[:merge_request_id]])
2021-04-17 20:07:23 +05:30
mapping[row[:sha]] = mr
2021-03-11 19:13:27 +05:30
end
end
2021-04-17 20:07:23 +05:30
mapping
2021-03-11 19:13:27 +05:30
end
end
end