James Moger
2015-11-22 ed552ba47c02779c270ffd62841d6d1048dade70
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.
699e71 42  *
d9f687 43  * @author James Moger
699e71 44  *
d9f687 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.
699e71 52      *
a2709d 53      * @param t
JM 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.
699e71 77      *
d9f687 78      * If the dateformat is unspecified an attempt is made to determine an
JM 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.
699e71 82      *
d9f687 83      * @param repository
JM 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) {
a59232 139                     Date d = JGitUtils.getAuthorDate(rev);
424fe1 140                     String p = df.format(d);
JM 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.
699e71 175      *
d9f687 176      * @param repository
JM 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                     }
ac7e9a 213                     p = p.replace('\n',' ').replace('\r',  ' ').trim();
424fe1 214                     if (!metricMap.containsKey(p)) {
JM 215                         metricMap.put(p, new Metric(p));
216                     }
217                     Metric m = metricMap.get(p);
218                     m.count++;
219                 }
220             } catch (Throwable t) {
a2709d 221                 error(t, repository, "{0} failed to mine log history for author metrics of {1}",
JM 222                         objectId);
424fe1 223             }
JM 224         }
225         List<String> keys = new ArrayList<String>(metricMap.keySet());
226         Collections.sort(keys);
227         List<Metric> metrics = new ArrayList<Metric>();
228         for (String key : keys) {
229             metrics.add(metricMap.get(key));
230         }
231         return metrics;
232     }
233 }