Class: MergeRequests::OldestPerCommitFinder

Inherits:
Object
  • Object
show all
Defined in:
app/finders/merge_requests/oldest_per_commit_finder.rb

Overview

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.

Instance Method Summary collapse

Constructor Details

#initialize(project) ⇒ OldestPerCommitFinder

Returns a new instance of OldestPerCommitFinder.



11
12
13
# File 'app/finders/merge_requests/oldest_per_commit_finder.rb', line 11

def initialize(project)
  @project = project
end

Instance Method Details

#execute(commits) ⇒ Object

Returns a Hash that maps a commit ID to the oldest merge request that introduced that commit.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'app/finders/merge_requests/oldest_per_commit_finder.rb', line 17

def execute(commits)
  mapping = {}
  shas = commits.map(&:id)

  # To include merge requests by the merge/squash SHA, we don't need to go
  # through any diff rows.
  #
  # 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
    .by_merge_or_squash_commit_sha(shas)
    .each do |mr|
      # 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
    end

  remaining = shas - mapping.keys

  return mapping if remaining.empty?

  id_rows = MergeRequestDiffCommit
    .oldest_merge_request_id_per_commit(@project.id, remaining)

  mrs = MergeRequest
    .preload_target_project
    .id_in(id_rows.map { |r| r[:merge_request_id] })
    .index_by(&:id)

  id_rows.each do |row|
    if (mr = mrs[row[:merge_request_id]])
      mapping[row[:sha]] = mr
    end
  end

  mapping
end