debian-mirror-gitlab/app/models/commit_collection.rb

117 lines
3.4 KiB
Ruby
Raw Normal View History

2018-03-17 18:26:18 +05:30
# frozen_string_literal: true
2020-03-13 15:44:24 +05:30
# A collection of Commit instances for a specific container and Git reference.
2018-03-17 18:26:18 +05:30
class CommitCollection
include Enumerable
2019-03-02 22:35:43 +05:30
include Gitlab::Utils::StrongMemoize
2018-03-17 18:26:18 +05:30
2020-03-13 15:44:24 +05:30
attr_reader :container, :ref, :commits
2018-03-17 18:26:18 +05:30
2020-03-13 15:44:24 +05:30
delegate :repository, to: :container, allow_nil: true
delegate :project, to: :repository, allow_nil: true
# container - The object the commits belong to.
2018-03-17 18:26:18 +05:30
# commits - The Commit instances to store.
# ref - The name of the ref (e.g. "master").
2020-03-13 15:44:24 +05:30
def initialize(container, commits, ref = nil)
@container = container
2018-03-17 18:26:18 +05:30
@commits = commits
@ref = ref
end
def each(&block)
commits.each(&block)
end
2019-07-07 11:18:12 +05:30
def committers
emails = without_merge_commits.map(&:committer_email).uniq
2019-03-02 22:35:43 +05:30
User.by_any_email(emails)
end
def without_merge_commits
strong_memoize(:without_merge_commits) do
2019-07-07 11:18:12 +05:30
# `#enrich!` the collection to ensure all commits contain
# the necessary parent data
enrich!.commits.reject(&:merge_commit?)
2019-03-02 22:35:43 +05:30
end
end
2019-12-21 20:55:43 +05:30
# Returns the collection with the latest pipeline for every commit pre-set.
#
# Setting the pipeline for each commit ahead of time removes the need for running
# a query for every commit we're displaying.
def with_latest_pipeline(ref = nil)
2020-03-13 15:44:24 +05:30
return self unless project
2019-12-21 20:55:43 +05:30
pipelines = project.ci_pipelines.latest_pipeline_per_commit(map(&:id), ref)
each do |commit|
2020-10-24 23:57:45 +05:30
pipeline = pipelines[commit.id]
pipeline&.number_of_warnings # preload number of warnings
commit.set_latest_pipeline_for_ref(ref, pipeline)
2019-12-21 20:55:43 +05:30
end
self
end
2020-07-28 23:09:34 +05:30
# Returns the collection with markdown fields preloaded.
#
# Get the markdown cache from redis using pipeline to prevent n+1 requests
# when rendering the markdown of an attribute (e.g. title, full_title,
# description).
def with_markdown_cache
Commit.preload_markdown_cache!(commits)
self
end
2019-07-07 11:18:12 +05:30
def unenriched
commits.reject(&:gitaly_commit?)
end
def fully_enriched?
unenriched.empty?
end
# Batch load any commits that are not backed by full gitaly data, and
# replace them in the collection.
def enrich!
2020-03-13 15:44:24 +05:30
# A container is needed in order to fetch data from gitaly. Containers
2019-07-07 11:18:12 +05:30
# can be absent from commits in certain rare situations (like when
# viewing a MR of a deleted fork). In these cases, assume that the
# enriched data is not needed.
2020-03-13 15:44:24 +05:30
return self if container.blank? || fully_enriched?
2019-07-07 11:18:12 +05:30
# Batch load full Commits from the repository
# and map to a Hash of id => Commit
replacements = Hash[unenriched.map do |c|
2020-03-13 15:44:24 +05:30
[c.id, Commit.lazy(container, c.id)]
2019-07-07 11:18:12 +05:30
end.compact]
# Replace the commits, keeping the same order
2019-12-21 20:55:43 +05:30
@commits = @commits.map do |original_commit|
# Return the original instance: if it didn't need to be batchloaded, it was
# already enriched.
batch_loaded_commit = replacements.fetch(original_commit.id, original_commit)
# If batch loading the commit failed, fall back to the original commit.
# We need to explicitly check `.nil?` since otherwise a `BatchLoader` instance
# that looks like `nil` is returned.
batch_loaded_commit.nil? ? original_commit : batch_loaded_commit
2018-03-17 18:26:18 +05:30
end
self
end
def respond_to_missing?(message, inc_private = false)
commits.respond_to?(message, inc_private)
end
# rubocop:disable GitlabSecurity/PublicSend
def method_missing(message, *args, &block)
commits.public_send(message, *args, &block)
end
end