Class: Repositories::ChangelogCommitsFinder

Inherits:
Object
  • Object
show all
Defined in:
app/finders/repositories/changelog_commits_finder.rb

Overview

Finder for getting the commits to include in a changelog.

Constant Summary collapse

COMMITS_PER_PAGE =

The maximum number of commits to retrieve per page.

This value is arbitrarily chosen. Lowering it means more Gitaly calls, but less data being loaded into memory at once. Increasing it has the opposite effect.

This amount is based around the number of commits that usually go in a GitLab release. Some examples for GitLab's own releases:

  • 13.6.0: 4636 commits

  • 13.5.0: 5912 commits

  • 13.4.0: 5541 commits

Using this limit should result in most (very large) projects only needing 5-10 Gitaly calls, while keeping memory usage at a reasonable amount.

1024
REVERT_REGEX =

The regex to use for extracting the SHA of a reverted commit.

/^This reverts commit (?<sha>[0-9a-f]{40})/i.freeze

Instance Method Summary collapse

Constructor Details

#initialize(project:, from:, to:, per_page: COMMITS_PER_PAGE) ⇒ ChangelogCommitsFinder

The `project` argument specifies the project for which to obtain the commits.

The `from` and `to` arguments specify the range of commits to include. The commit specified in `from` won't be included itself. The commit specified in `to` is included.

The `per_page` argument specifies how many commits are retrieved in a single Gitaly API call.


35
36
37
38
39
40
# File 'app/finders/repositories/changelog_commits_finder.rb', line 35

def initialize(project:, from:, to:, per_page: COMMITS_PER_PAGE)
  @project = project
  @from = from
  @to = to
  @per_page = per_page
end

Instance Method Details

#each_page(trailer) ⇒ Object

Fetches all commits that have the given trailer set.

The commits are yielded to the supplied block in batches. This allows other code to process these commits in batches too, instead of first having to load all commits into memory.

Example:

ChangelogCommitsFinder.new(...).each_page('Changelog') do |commits|
  commits.each do |commit|
    ...
  end
end

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'app/finders/repositories/changelog_commits_finder.rb', line 55

def each_page(trailer)
  return to_enum(__method__, trailer) unless block_given?

  offset = 0
  reverted = Set.new
  response = fetch_commits

  while response.any?
    commits = []

    response.each do |commit|
      # If the commit is reverted in the same range (by a newer commit), we
      # won't include it. This works here because commits are processed in
      # reverse order (= newer first).
      next if reverted.include?(commit.id)

      if (sha = revert_commit_sha(commit))
        reverted << sha
      end

      commits.push(commit) if commit.trailers.key?(trailer)
    end

    yield commits

    offset += response.length
    response = fetch_commits(offset)
  end
end