summaryrefslogtreecommitdiff
path: root/app/models/commit.rb
blob: 5c6b4d88d9673584d97c5eac2ae96af117048a1d (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
65
66
67
68
69
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
class Commit
  include ActiveModel::Conversion
  include Gitlab::Encode
  extend ActiveModel::Naming

  attr_accessor :commit
  attr_accessor :head
  attr_accessor :refs

  delegate :message,
    :authored_date,
    :committed_date,
    :parents,
    :sha,
    :date,
    :committer,
    :author,
    :message,
    :diffs,
    :tree,
    :id,
    :to_patch,
    to: :commit


  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
      Commit.new(commit) if commit
    end

    def fresh_commits(repo, n = 10)
      commits = repo.heads.map do |h|
        repo.commits(h.name, n).map { |c| Commit.new(c, h) }
      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)
      commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }

      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|
        repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) }
      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)
      end.map{ |c| Commit.new(c) }
    end

    def commits_between(repo, from, to)
      repo.commits_between(from, to).map { |c| Commit.new(c) }
    end

    def compare(project, from, to)
      first = project.commit(to.try(:strip))
      last = project.commit(from.try(:strip))

      result = { 
        commits: [],
        diffs: [],
        commit: nil
      }

      if first && last
        commits = [first, last].sort_by(&:created_at)
        younger = commits.first
        older = commits.last

        result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)}
        result[:diffs] = project.repo.diff(younger.id, older.id) rescue []
        result[:commit] = Commit.new(older)
      end

      result
    end
  end

  def persisted?
    false
  end

  def initialize(raw_commit, head = nil)
    @commit = raw_commit
    @head = head
  end

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

  def safe_message
    utf8 message
  end

  def created_at
    committed_date
  end

  def author_email
    author.email
  end

  def author_name
    utf8 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
    utf8 committer.name
  end

  def committer_email
    committer.email
  end

  def prev_commit
    parents.try :first
  end

  def prev_commit_id
    prev_commit.try :id
  end

  def parents_count 
    parents && parents.count || 0
  end
end