From cedf138f3c9afeae7bcbda5dbb0511ebec297d10 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 10 Jun 2013 18:45:32 -0400 Subject: [PATCH] Globl and per-repository setting to exclude authors form metrics (issue-251) --- releases.moxie | 2 ++ src/main/distrib/data/gitblit.properties | 7 +++++ src/main/java/com/gitblit/GitBlit.java | 3 ++ .../java/com/gitblit/models/Activity.java | 30 +++++++++++++++---- .../com/gitblit/models/RepositoryModel.java | 3 +- .../java/com/gitblit/utils/ActivityUtils.java | 16 +++++++++- .../wicket/charting/GooglePieChart.java | 25 ++++++++++++++-- .../gitblit/wicket/pages/DashboardPage.java | 30 +++++++++++++++---- .../wicket/pages/EditRepositoryPage.html | 15 +++++----- .../wicket/pages/EditRepositoryPage.java | 23 ++++++++++++++ 10 files changed, 131 insertions(+), 23 deletions(-) diff --git a/releases.moxie b/releases.moxie index 0a73d5bb..d5c04ae2 100644 --- a/releases.moxie +++ b/releases.moxie @@ -42,6 +42,7 @@ r17: { - Updated Japanese translation additions: + - Global and per-repository setting to exclude authors from metrics (issue-251) - Added SalesForce.com user service - Added simple star/unstar function to flag or bookmark interesting repositories - Added Dashboard page which shows a news feed for starred repositories and offers a filterable list of repositories you care about @@ -110,6 +111,7 @@ r17: { - { name: 'web.activityDurationChoices', defaultValue: '7 14 28 60 90 180' } - { name: 'web.allowAppCloneLinks', defaultValue: true } - { name: 'web.forceDefaultLocale', defaultValue: ' ' } + - { name: 'web.metricAuthorExclusions', defaultValue: ' ' } - { name: 'web.overviewPushCount', defaultValue: 5 } - { name: 'web.pushesPerPage', defaultValue: 10 } - { name: 'server.nioThreadPoolSize', defaultValue: 50 } diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index a6dc3158..1671507f 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -826,6 +826,13 @@ web.activityDuration = 7 # SINCE 1.3.0 web.activityDurationChoices = 7 14 28 60 90 180 +# Case-insensitive list of authors to exclude from metrics. Useful for +# eliminating bots. +# +# SPACE-DELIMITED +# SINCE 1.3.0 +web.metricAuthorExclusions = + # The number of commits to display on the summary page # Value must exceed 0 else default of 20 is used # diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java index ceb40c13..df17edd9 100644 --- a/src/main/java/com/gitblit/GitBlit.java +++ b/src/main/java/com/gitblit/GitBlit.java @@ -1939,6 +1939,8 @@ public class GitBlit implements ServletContextListener { Constants.CONFIG_GITBLIT, null, "mailingList"))); model.indexedBranches = new ArrayList(Arrays.asList(config.getStringList( Constants.CONFIG_GITBLIT, null, "indexBranch"))); + model.metricAuthorExclusions = new ArrayList(Arrays.asList(config.getStringList( + Constants.CONFIG_GITBLIT, null, "metricAuthorExclusions"))); // Custom defined properties model.customFields = new LinkedHashMap(); @@ -2465,6 +2467,7 @@ public class GitBlit implements ServletContextListener { updateList(config, "postReceiveScript", repository.postReceiveScripts); updateList(config, "mailingList", repository.mailingLists); updateList(config, "indexBranch", repository.indexedBranches); + updateList(config, "metricAuthorExclusions", repository.metricAuthorExclusions); // User Defined Properties if (repository.customFields != null) { diff --git a/src/main/java/com/gitblit/models/Activity.java b/src/main/java/com/gitblit/models/Activity.java index 59405c7f..547c348f 100644 --- a/src/main/java/com/gitblit/models/Activity.java +++ b/src/main/java/com/gitblit/models/Activity.java @@ -17,6 +17,7 @@ package com.gitblit.models; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -24,6 +25,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import org.eclipse.jgit.revwalk.RevCommit; @@ -43,13 +45,15 @@ public class Activity implements Serializable, Comparable { public final Date startDate; public final Date endDate; - + private final Set commits; private final Map authorMetrics; private final Map repositoryMetrics; + private final Set authorExclusions; + /** * Constructor for one day of activity. * @@ -73,6 +77,18 @@ public class Activity implements Serializable, Comparable { commits = new LinkedHashSet(); authorMetrics = new HashMap(); repositoryMetrics = new HashMap(); + authorExclusions = new TreeSet(); + } + + /** + * Exclude the specified authors from the metrics. + * + * @param authors + */ + public void excludeAuthors(Collection authors) { + for (String author : authors) { + authorExclusions.add(author.toLowerCase()); + } } /** @@ -88,16 +104,20 @@ public class Activity implements Serializable, Comparable { public RepositoryCommit addCommit(String repository, String branch, RevCommit commit) { RepositoryCommit commitModel = new RepositoryCommit(repository, branch, commit); if (commits.add(commitModel)) { + String author = StringUtils.removeNewlines(commit.getAuthorIdent().getName()); + String authorName = author.toLowerCase(); + String authorEmail = StringUtils.removeNewlines(commit.getAuthorIdent().getEmailAddress()).toLowerCase(); if (!repositoryMetrics.containsKey(repository)) { repositoryMetrics.put(repository, new Metric(repository)); } repositoryMetrics.get(repository).count++; - String author = StringUtils.removeNewlines(commit.getAuthorIdent().getEmailAddress()).toLowerCase(); - if (!authorMetrics.containsKey(author)) { - authorMetrics.put(author, new Metric(author)); + if (!authorExclusions.contains(authorName) && !authorExclusions.contains(authorEmail)) { + if (!authorMetrics.containsKey(author)) { + authorMetrics.put(author, new Metric(author)); + } + authorMetrics.get(author).count++; } - authorMetrics.get(author).count++; return commitModel; } return null; diff --git a/src/main/java/com/gitblit/models/RepositoryModel.java b/src/main/java/com/gitblit/models/RepositoryModel.java index 0e39d912..5eb51b4b 100644 --- a/src/main/java/com/gitblit/models/RepositoryModel.java +++ b/src/main/java/com/gitblit/models/RepositoryModel.java @@ -81,7 +81,8 @@ public class RepositoryModel implements Serializable, Comparable metricAuthorExclusions; public transient boolean isCollectingGarbage; public Date lastGC; diff --git a/src/main/java/com/gitblit/utils/ActivityUtils.java b/src/main/java/com/gitblit/utils/ActivityUtils.java index 015e8d3d..edeb01ad 100644 --- a/src/main/java/com/gitblit/utils/ActivityUtils.java +++ b/src/main/java/com/gitblit/utils/ActivityUtils.java @@ -27,7 +27,9 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TimeZone; +import java.util.TreeSet; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -35,6 +37,7 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import com.gitblit.GitBlit; +import com.gitblit.Keys; import com.gitblit.models.Activity; import com.gitblit.models.GravatarProfile; import com.gitblit.models.RefModel; @@ -78,6 +81,15 @@ public class ActivityUtils { df.setTimeZone(timezone); Calendar cal = Calendar.getInstance(); cal.setTimeZone(timezone); + + // aggregate author exclusions + Set authorExclusions = new TreeSet(); + authorExclusions.addAll(GitBlit.getStrings(Keys.web.metricAuthorExclusions)); + for (RepositoryModel model : models) { + if (!ArrayUtils.isEmpty(model.metricAuthorExclusions)) { + authorExclusions.addAll(model.metricAuthorExclusions); + } + } Map activity = new HashMap(); for (RepositoryModel model : models) { @@ -124,7 +136,9 @@ public class ActivityUtils { cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); - activity.put(dateStr, new Activity(cal.getTime())); + Activity a = new Activity(cal.getTime()); + a.excludeAuthors(authorExclusions); + activity.put(dateStr, a); } RepositoryCommit commitModel = activity.get(dateStr) .addCommit(model.name, shortName, commit); diff --git a/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java b/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java index 945e08b1..a9b46670 100644 --- a/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java +++ b/src/main/java/com/gitblit/wicket/charting/GooglePieChart.java @@ -16,7 +16,9 @@ package com.gitblit.wicket.charting; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import com.gitblit.utils.StringUtils; @@ -44,10 +46,27 @@ public class GooglePieChart extends GoogleChart { line(sb, MessageFormat.format("{0}.addRows({1,number,0});", dName, values.size())); Collections.sort(values); - - StringBuilder colors = new StringBuilder("colors:["); - for (int i = 0; i < values.size(); i++) { + List list = new ArrayList(); + + int maxSlices = 10; + int maxCount = Math.min(maxSlices - 1, values.size()); + + for (int i = 0; i < maxCount; i++) { ChartValue value = values.get(i); + list.add(value); + } + if (values.size() >= maxSlices) { + float others = 0; + for (int i = maxSlices - 1; i < values.size(); i++) { + others += values.get(i).value; + } + ChartValue other = new ChartValue("other", others); + list.add(other); + } + + StringBuilder colors = new StringBuilder("colors:["); + for (int i = 0; i < list.size(); i++) { + ChartValue value = list.get(i); colors.append('\''); colors.append(StringUtils.getColor(value.name)); colors.append('\''); diff --git a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java index 39771aef..66bbf734 100644 --- a/src/main/java/com/gitblit/wicket/pages/DashboardPage.java +++ b/src/main/java/com/gitblit/wicket/pages/DashboardPage.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; +import java.util.TreeSet; import org.apache.wicket.Component; import org.apache.wicket.PageParameters; @@ -187,7 +188,20 @@ public class DashboardPage extends RootPage { // add the nifty charts if (!ArrayUtils.isEmpty(pushes)) { - GoogleCharts charts = createCharts(pushes); + // aggregate author exclusions + Set authorExclusions = new TreeSet(); + for (String author : GitBlit.getStrings(Keys.web.metricAuthorExclusions)) { + authorExclusions.add(author.toLowerCase()); + } + for (RepositoryModel model : feedSources) { + if (!ArrayUtils.isEmpty(model.metricAuthorExclusions)) { + for (String author : model.metricAuthorExclusions) { + authorExclusions.add(author.toLowerCase()); + } + } + } + + GoogleCharts charts = createCharts(pushes, authorExclusions); add(new HeaderContributor(charts)); } @@ -359,7 +373,7 @@ public class DashboardPage extends RootPage { * @param recentPushes * @return */ - private GoogleCharts createCharts(List recentPushes) { + private GoogleCharts createCharts(List recentPushes, Set authorExclusions) { // activity metrics Map repositoryMetrics = new HashMap(); Map authorMetrics = new HashMap(); @@ -375,11 +389,15 @@ public class DashboardPage extends RootPage { repositoryMetrics.get(repository).count += 1; for (RepositoryCommit commit : push.getCommits()) { - String author = commit.getAuthorIdent().getName(); - if (!authorMetrics.containsKey(author)) { - authorMetrics.put(author, new Metric(author)); + String author = StringUtils.removeNewlines(commit.getAuthorIdent().getName()); + String authorName = author.toLowerCase(); + String authorEmail = StringUtils.removeNewlines(commit.getAuthorIdent().getEmailAddress()).toLowerCase(); + if (!authorExclusions.contains(authorName) && !authorExclusions.contains(authorEmail)) { + if (!authorMetrics.containsKey(author)) { + authorMetrics.put(author, new Metric(author)); + } + authorMetrics.get(author).count += 1; } - authorMetrics.get(author).count += 1; } } diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html index f8ecb992..38070273 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -41,8 +41,9 @@
- + @@ -51,15 +52,15 @@
- + - + - - - + + + @@ -72,7 +73,7 @@





- +
diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index 938b05e3..4c471a1e 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -76,6 +76,8 @@ public class EditRepositoryPage extends RootSubPage { RepositoryModel repositoryModel; + private IModel metricAuthorExclusions; + private IModel mailingLists; public EditRepositoryPage() { @@ -316,6 +318,23 @@ public class EditRepositoryPage extends RootSubPage { } } + // set author metric exclusions + String ax = metricAuthorExclusions.getObject(); + if (!StringUtils.isEmpty(ax)) { + Set list = new HashSet(); + for (String exclusion : StringUtils.getStringsFromValue(ax, " ")) { + if (StringUtils.isEmpty(exclusion)) { + continue; + } + if (exclusion.indexOf(' ') > -1) { + list.add("\"" + exclusion + "\""); + } else { + list.add(exclusion); + } + } + repositoryModel.metricAuthorExclusions = new ArrayList(list); + } + // set mailing lists String ml = mailingLists.getObject(); if (!StringUtils.isEmpty(ml)) { @@ -435,6 +454,10 @@ public class EditRepositoryPage extends RootSubPage { List maxActivityCommits = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500 ); form.add(new DropDownChoice("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer())); + metricAuthorExclusions = new Model(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? "" + : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " ")); + form.add(new TextField("metricAuthorExclusions", metricAuthorExclusions)); + mailingLists = new Model(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? "" : StringUtils.flattenStrings(repositoryModel.mailingLists, " ")); form.add(new TextField("mailingLists", mailingLists)); -- 2.39.5