You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MetricUtils.java 7.2KB

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