commit | author | age
|
424fe1
|
1 |
/*
|
JM |
2 |
* Copyright 2011 gitblit.com.
|
|
3 |
*
|
|
4 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5 |
* you may not use this file except in compliance with the License.
|
|
6 |
* You may obtain a copy of the License at
|
|
7 |
*
|
|
8 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9 |
*
|
|
10 |
* Unless required by applicable law or agreed to in writing, software
|
|
11 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13 |
* See the License for the specific language governing permissions and
|
|
14 |
* limitations under the License.
|
|
15 |
*/
|
|
16 |
package com.gitblit.utils;
|
|
17 |
|
|
18 |
import java.text.DateFormat;
|
a2709d
|
19 |
import java.text.MessageFormat;
|
424fe1
|
20 |
import java.text.SimpleDateFormat;
|
JM |
21 |
import java.util.ArrayList;
|
|
22 |
import java.util.Collections;
|
|
23 |
import java.util.Date;
|
|
24 |
import java.util.HashMap;
|
|
25 |
import java.util.List;
|
|
26 |
import java.util.Map;
|
40538c
|
27 |
import java.util.TimeZone;
|
424fe1
|
28 |
|
JM |
29 |
import org.eclipse.jgit.lib.ObjectId;
|
|
30 |
import org.eclipse.jgit.lib.Repository;
|
|
31 |
import org.eclipse.jgit.revwalk.RevCommit;
|
|
32 |
import org.eclipse.jgit.revwalk.RevWalk;
|
|
33 |
import org.slf4j.Logger;
|
|
34 |
import org.slf4j.LoggerFactory;
|
|
35 |
|
|
36 |
import com.gitblit.models.Metric;
|
|
37 |
import com.gitblit.models.RefModel;
|
|
38 |
|
d9f687
|
39 |
/**
|
JM |
40 |
* Utility class for collecting metrics on a branch, tag, or other ref within
|
|
41 |
* the repository.
|
|
42 |
*
|
|
43 |
* @author James Moger
|
|
44 |
*
|
|
45 |
*/
|
424fe1
|
46 |
public class MetricUtils {
|
JM |
47 |
|
|
48 |
private static final Logger LOGGER = LoggerFactory.getLogger(MetricUtils.class);
|
|
49 |
|
d9f687
|
50 |
/**
|
a2709d
|
51 |
* Log an error message and exception.
|
JM |
52 |
*
|
|
53 |
* @param t
|
|
54 |
* @param repository
|
|
55 |
* if repository is not null it MUST be the {0} parameter in the
|
|
56 |
* pattern.
|
|
57 |
* @param pattern
|
|
58 |
* @param objects
|
|
59 |
*/
|
|
60 |
private static void error(Throwable t, Repository repository, String pattern, Object... objects) {
|
|
61 |
List<Object> parameters = new ArrayList<Object>();
|
|
62 |
if (objects != null && objects.length > 0) {
|
|
63 |
for (Object o : objects) {
|
|
64 |
parameters.add(o);
|
|
65 |
}
|
|
66 |
}
|
|
67 |
if (repository != null) {
|
|
68 |
parameters.add(0, repository.getDirectory().getAbsolutePath());
|
|
69 |
}
|
|
70 |
LOGGER.error(MessageFormat.format(pattern, parameters.toArray()), t);
|
|
71 |
}
|
|
72 |
|
|
73 |
/**
|
d9f687
|
74 |
* Returns the list of metrics for the specified commit reference, branch,
|
JM |
75 |
* or tag within the repository. If includeTotal is true, the total of all
|
|
76 |
* the metrics will be included as the first element in the returned list.
|
|
77 |
*
|
|
78 |
* If the dateformat is unspecified an attempt is made to determine an
|
|
79 |
* appropriate date format by determining the time difference between the
|
|
80 |
* first commit on the branch and the most recent commit. This assumes that
|
|
81 |
* the commits are linear.
|
|
82 |
*
|
|
83 |
* @param repository
|
|
84 |
* @param objectId
|
|
85 |
* if null or empty, HEAD is assumed.
|
|
86 |
* @param includeTotal
|
|
87 |
* @param dateFormat
|
40538c
|
88 |
* @param timezone
|
d9f687
|
89 |
* @return list of metrics
|
JM |
90 |
*/
|
|
91 |
public static List<Metric> getDateMetrics(Repository repository, String objectId,
|
40538c
|
92 |
boolean includeTotal, String dateFormat, TimeZone timezone) {
|
424fe1
|
93 |
Metric total = new Metric("TOTAL");
|
JM |
94 |
final Map<String, Metric> metricMap = new HashMap<String, Metric>();
|
a2709d
|
95 |
|
d9f687
|
96 |
if (JGitUtils.hasCommits(repository)) {
|
JM |
97 |
final List<RefModel> tags = JGitUtils.getTags(repository, true, -1);
|
424fe1
|
98 |
final Map<ObjectId, RefModel> tagMap = new HashMap<ObjectId, RefModel>();
|
JM |
99 |
for (RefModel tag : tags) {
|
4ab184
|
100 |
tagMap.put(tag.getReferencedObjectId(), tag);
|
424fe1
|
101 |
}
|
d9f687
|
102 |
RevWalk revWalk = null;
|
424fe1
|
103 |
try {
|
a2709d
|
104 |
// resolve branch
|
JM |
105 |
ObjectId branchObject;
|
|
106 |
if (StringUtils.isEmpty(objectId)) {
|
|
107 |
branchObject = JGitUtils.getDefaultBranch(repository);
|
|
108 |
} else {
|
|
109 |
branchObject = repository.resolve(objectId);
|
|
110 |
}
|
671c19
|
111 |
|
d9f687
|
112 |
revWalk = new RevWalk(repository);
|
a2709d
|
113 |
RevCommit lastCommit = revWalk.parseCommit(branchObject);
|
d9f687
|
114 |
revWalk.markStart(lastCommit);
|
a125cf
|
115 |
|
JM |
116 |
DateFormat df;
|
d9f687
|
117 |
if (StringUtils.isEmpty(dateFormat)) {
|
a125cf
|
118 |
// dynamically determine date format
|
671c19
|
119 |
RevCommit firstCommit = JGitUtils.getFirstCommit(repository,
|
JM |
120 |
branchObject.getName());
|
a125cf
|
121 |
int diffDays = (lastCommit.getCommitTime() - firstCommit.getCommitTime())
|
JM |
122 |
/ (60 * 60 * 24);
|
|
123 |
total.duration = diffDays;
|
1fa5e8
|
124 |
if (diffDays <= 365) {
|
a125cf
|
125 |
// Days
|
JM |
126 |
df = new SimpleDateFormat("yyyy-MM-dd");
|
|
127 |
} else {
|
|
128 |
// Months
|
|
129 |
df = new SimpleDateFormat("yyyy-MM");
|
|
130 |
}
|
|
131 |
} else {
|
|
132 |
// use specified date format
|
d9f687
|
133 |
df = new SimpleDateFormat(dateFormat);
|
a125cf
|
134 |
}
|
40538c
|
135 |
df.setTimeZone(timezone);
|
a125cf
|
136 |
|
d9f687
|
137 |
Iterable<RevCommit> revlog = revWalk;
|
424fe1
|
138 |
for (RevCommit rev : revlog) {
|
JM |
139 |
Date d = JGitUtils.getCommitDate(rev);
|
|
140 |
String p = df.format(d);
|
|
141 |
if (!metricMap.containsKey(p)) {
|
|
142 |
metricMap.put(p, new Metric(p));
|
|
143 |
}
|
|
144 |
Metric m = metricMap.get(p);
|
|
145 |
m.count++;
|
|
146 |
total.count++;
|
|
147 |
if (tagMap.containsKey(rev.getId())) {
|
|
148 |
m.tag++;
|
|
149 |
total.tag++;
|
|
150 |
}
|
|
151 |
}
|
|
152 |
} catch (Throwable t) {
|
a2709d
|
153 |
error(t, repository, "{0} failed to mine log history for date metrics of {1}",
|
JM |
154 |
objectId);
|
d9f687
|
155 |
} finally {
|
JM |
156 |
if (revWalk != null) {
|
|
157 |
revWalk.dispose();
|
|
158 |
}
|
424fe1
|
159 |
}
|
JM |
160 |
}
|
|
161 |
List<String> keys = new ArrayList<String>(metricMap.keySet());
|
|
162 |
Collections.sort(keys);
|
|
163 |
List<Metric> metrics = new ArrayList<Metric>();
|
|
164 |
for (String key : keys) {
|
|
165 |
metrics.add(metricMap.get(key));
|
|
166 |
}
|
|
167 |
if (includeTotal) {
|
|
168 |
metrics.add(0, total);
|
|
169 |
}
|
|
170 |
return metrics;
|
|
171 |
}
|
|
172 |
|
d9f687
|
173 |
/**
|
JM |
174 |
* Returns a list of author metrics for the specified repository.
|
|
175 |
*
|
|
176 |
* @param repository
|
|
177 |
* @param objectId
|
|
178 |
* if null or empty, HEAD is assumed.
|
|
179 |
* @param byEmailAddress
|
|
180 |
* group metrics by author email address otherwise by author name
|
|
181 |
* @return list of metrics
|
|
182 |
*/
|
|
183 |
public static List<Metric> getAuthorMetrics(Repository repository, String objectId,
|
|
184 |
boolean byEmailAddress) {
|
424fe1
|
185 |
final Map<String, Metric> metricMap = new HashMap<String, Metric>();
|
d9f687
|
186 |
if (JGitUtils.hasCommits(repository)) {
|
424fe1
|
187 |
try {
|
d9f687
|
188 |
RevWalk walk = new RevWalk(repository);
|
a2709d
|
189 |
// resolve branch
|
JM |
190 |
ObjectId branchObject;
|
|
191 |
if (StringUtils.isEmpty(objectId)) {
|
|
192 |
branchObject = JGitUtils.getDefaultBranch(repository);
|
|
193 |
} else {
|
|
194 |
branchObject = repository.resolve(objectId);
|
|
195 |
}
|
|
196 |
RevCommit lastCommit = walk.parseCommit(branchObject);
|
424fe1
|
197 |
walk.markStart(lastCommit);
|
a125cf
|
198 |
|
424fe1
|
199 |
Iterable<RevCommit> revlog = walk;
|
JM |
200 |
for (RevCommit rev : revlog) {
|
a125cf
|
201 |
String p;
|
d9f687
|
202 |
if (byEmailAddress) {
|
5cc4f2
|
203 |
p = rev.getAuthorIdent().getEmailAddress().toLowerCase();
|
a125cf
|
204 |
if (StringUtils.isEmpty(p)) {
|
5cc4f2
|
205 |
p = rev.getAuthorIdent().getName().toLowerCase();
|
a125cf
|
206 |
}
|
JM |
207 |
} else {
|
5cc4f2
|
208 |
p = rev.getAuthorIdent().getName().toLowerCase();
|
a125cf
|
209 |
if (StringUtils.isEmpty(p)) {
|
5cc4f2
|
210 |
p = rev.getAuthorIdent().getEmailAddress().toLowerCase();
|
a125cf
|
211 |
}
|
424fe1
|
212 |
}
|
JM |
213 |
if (!metricMap.containsKey(p)) {
|
|
214 |
metricMap.put(p, new Metric(p));
|
|
215 |
}
|
|
216 |
Metric m = metricMap.get(p);
|
|
217 |
m.count++;
|
|
218 |
}
|
|
219 |
} catch (Throwable t) {
|
a2709d
|
220 |
error(t, repository, "{0} failed to mine log history for author metrics of {1}",
|
JM |
221 |
objectId);
|
424fe1
|
222 |
}
|
JM |
223 |
}
|
|
224 |
List<String> keys = new ArrayList<String>(metricMap.keySet());
|
|
225 |
Collections.sort(keys);
|
|
226 |
List<Metric> metrics = new ArrayList<Metric>();
|
|
227 |
for (String key : keys) {
|
|
228 |
metrics.add(metricMap.get(key));
|
|
229 |
}
|
|
230 |
return metrics;
|
|
231 |
}
|
|
232 |
}
|