commit.rb 3.8 KB
Newer Older
1
# Gitlab::Git::Commit is a wrapper around native Grit::Commit object
2 3 4 5
# We dont want to use grit objects inside app/
# It helps us easily migrate to rugged in future
module Gitlab
  module Git
6
    class Commit
7 8 9
      attr_accessor :raw_commit, :head, :refs

      delegate  :message, :authored_date, :committed_date, :parents, :sha,
10 11
        :date, :committer, :author, :diffs, :tree, :id, :stats, :to_patch,
        to: :raw_commit
12 13 14 15 16 17 18 19 20

      class << self
        def find_or_first(repo, commit_id = nil, root_ref)
          commit = if commit_id
                     repo.commit(commit_id)
                   else
                     repo.commits(root_ref).first
                   end

21
          Commit.new(commit) if commit
22 23 24 25
        end

        def fresh_commits(repo, n = 10)
          commits = repo.heads.map do |h|
26
            repo.commits(h.name, n).map { |c| Commit.new(c, h) }
27 28 29 30 31 32 33 34 35 36
          end.flatten.uniq { |c| c.id }

          commits.sort! do |x, y|
            y.committed_date <=> x.committed_date
          end

          commits[0...n]
        end

        def commits_with_refs(repo, n = 20)
37
          commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }
38 39 40 41 42 43 44 45 46 47

          commits.sort! do |x, y|
            y.committed_date <=> x.committed_date
          end

          commits[0..n]
        end

        def commits_since(repo, date)
          commits = repo.heads.map do |h|
48
            repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) }
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
          end.flatten.uniq { |c| c.id }

          commits.sort! do |x, y|
            y.committed_date <=> x.committed_date
          end

          commits
        end

        def commits(repo, ref, path = nil, limit = nil, offset = nil)
          if path
            repo.log(ref, path, max_count: limit, skip: offset)
          elsif limit && offset
            repo.commits(ref, limit, offset)
          else
            repo.commits(ref)
65
          end.map{ |c| Commit.new(c) }
66 67 68
        end

        def commits_between(repo, from, to)
69
          repo.commits_between(from, to).map { |c| Commit.new(c) }
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
        end
      end

      def initialize(raw_commit, head = nil)
        raise "Nil as raw commit passed" unless raw_commit

        @raw_commit = raw_commit
        @head = head
      end

      def short_id(length = 10)
        id.to_s[0..length]
      end

      def safe_message
        @safe_message ||= message
      end

      def created_at
        committed_date
      end

      def author_email
        author.email
      end

      def author_name
        author.name
      end

      # Was this commit committed by a different person than the original author?
      def different_committer?
        author_name != committer_name || author_email != committer_email
      end

      def committer_name
        committer.name
      end

      def committer_email
        committer.email
      end

      def prev_commit
        @prev_commit ||= if parents.present?
115
                           Commit.new(parents.first)
116 117 118 119 120 121 122 123 124 125 126 127 128
                         else
                           nil
                         end
      end

      def prev_commit_id
        prev_commit.try :id
      end

      # Shows the diff between the commit's parent and the commit.
      #
      # Cuts out the header and stats from #to_patch and returns only the diff.
      def to_diff
129
        # see Grit::Commit#show
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
        patch = to_patch

        # discard lines before the diff
        lines = patch.split("\n")
        while !lines.first.start_with?("diff --git") do
          lines.shift
        end
        lines.pop if lines.last =~ /^[\d.]+$/ # Git version
          lines.pop if lines.last == "-- "      # end of diff
        lines.join("\n")
      end

      def has_zero_stats?
        stats.total.zero?
      rescue
        true
      end
147 148 149 150

      def no_commit_message
        "--no commit message"
      end
151 152 153
    end
  end
end