summaryrefslogtreecommitdiff
path: root/lib/booru/commit_history.rb
blob: 723bbea5d5e3f7da7e326540efb07c793ae9ba6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
63
64
# frozen_string_literal: true

require 'rugged'
require_relative 'commit_info'

module Booru
  # Provides an interface to walk through the commit history
  # of the application repository.
  class CommitHistory
    include Enumerable

    # Creates a new history walker.
    def initialize
      #noinspection RubyArgCount
      @repo = Rugged::Repository.new(Rails.root.to_s)
    end

    # @overload def each
    #   Creates an enumerator to the commit history.
    #   @return [Enumerable] An enumerator.
    #
    # @overload def each(&block)
    #   Walks the commit history, yielding a {CommitInfo}
    #   for each commit in turn.
    #   @return [Enumerable] An enumerator.
    #
    # @see CommitInfo
    def each
      # Nothing to call.
      return self unless block_given?

      #noinspection RubyArgCount
      walker = Rugged::Walker.new(@repo)
      walker.sorting(Rugged::SORT_TOPO)
      walker.push('HEAD')

      walker.each do |c|
        # Commits with multiple parents are merge commits.
        #
        # Merge commits have multiple possible diffs, depending on which parent
        # tree is visited, and are mostly irrelevant to actual changes in the
        # state of the repository. They are ignored for the purposes of this
        # application.
        next if c.parents.size != 1

        diff = c.parents[0].diff(c)

        _, diff_insertions, diff_deletions = diff.stat

        yield CommitInfo.new(
          id:         c.oid.to_s,
          time:       c.time,
          name:       c.author[:name],
          email:      c.author[:email],
          message:    c.message,
          insertions: diff_insertions,
          deletions:  diff_deletions
        )
      end

      self
    end
  end
end