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
162
163
164
165
166
167
168
|
class Commit
include ActiveModel::Conversion
include StaticModel
extend ActiveModel::Naming
# Safe amount of files with diffs in one commit to render
# Used to prevent 500 error on huge commits by suppressing diff
#
DIFF_SAFE_SIZE = 100
attr_accessor :commit, :head, :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)
result = {
commits: [],
diffs: [],
commit: nil,
same: false
}
return result unless from && to
first = project.commit(to.try(:strip))
last = project.commit(from.try(:strip))
if first && last
commits = [first, last].sort_by(&:created_at)
younger = commits.first
older = commits.last
result[:same] = (younger.id == older.id)
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 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
@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
parents.try :first
end
def prev_commit_id
prev_commit.try :id
end
def parents_count
parents && parents.count || 0
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
# see Grit::Commit#show
patch = to_patch
# discard lines before the diff
lines = patch.split("\n")
while !lines.first.start_with?("diff --git") do
lines.shift
end
lines.join("\n")
end
end
|