]> source.dussan.org Git - gitblit.git/commitdiff
Globl and per-repository setting to exclude authors form metrics (issue-251)
authorJames Moger <james.moger@gitblit.com>
Mon, 10 Jun 2013 22:45:32 +0000 (18:45 -0400)
committerJames Moger <james.moger@gitblit.com>
Mon, 10 Jun 2013 22:45:32 +0000 (18:45 -0400)
releases.moxie
src/main/distrib/data/gitblit.properties
src/main/java/com/gitblit/GitBlit.java
src/main/java/com/gitblit/models/Activity.java
src/main/java/com/gitblit/models/RepositoryModel.java
src/main/java/com/gitblit/utils/ActivityUtils.java
src/main/java/com/gitblit/wicket/charting/GooglePieChart.java
src/main/java/com/gitblit/wicket/pages/DashboardPage.java
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java

index 0a73d5bbee5d2c6059d5c263cc0a37ce106d6bfb..d5c04ae29792f6bda277e73b1fe22aa2b25ce50b 100644 (file)
@@ -42,6 +42,7 @@ r17: {
         - Updated Japanese translation\r
         \r
     additions: \r
+        - Global and per-repository setting to exclude authors from metrics (issue-251)\r
         - Added SalesForce.com user service\r
      - Added simple star/unstar function to flag or bookmark interesting repositories\r
      - Added Dashboard page which shows a news feed for starred repositories and offers a filterable list of repositories you care about\r
@@ -110,6 +111,7 @@ r17: {
        - { name: 'web.activityDurationChoices', defaultValue: '7 14 28 60 90 180' }\r
        - { name: 'web.allowAppCloneLinks', defaultValue: true }\r
        - { name: 'web.forceDefaultLocale', defaultValue: ' ' }\r
+       - { name: 'web.metricAuthorExclusions', defaultValue: ' ' }\r
        - { name: 'web.overviewPushCount', defaultValue: 5 }\r
        - { name: 'web.pushesPerPage', defaultValue: 10 }\r
        - { name: 'server.nioThreadPoolSize', defaultValue: 50 }\r
index a6dc3158ca6521feac760144a4c344199f8180c3..1671507f192c581362160ff8453db2f04dd8321a 100644 (file)
@@ -826,6 +826,13 @@ web.activityDuration = 7
 # SINCE 1.3.0\r
 web.activityDurationChoices = 7 14 28 60 90 180\r
 \r
+# Case-insensitive list of authors to exclude from metrics.  Useful for\r
+# eliminating bots.\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 1.3.0\r
+web.metricAuthorExclusions =\r
+\r
 # The number of commits to display on the summary page\r
 # Value must exceed 0 else default of 20 is used\r
 #\r
index ceb40c132a8b1c99019a0ebe49de52afda1a946f..df17edd900cd628659445acef6c538a465393cbe 100644 (file)
@@ -1939,6 +1939,8 @@ public class GitBlit implements ServletContextListener {
                                        Constants.CONFIG_GITBLIT, null, "mailingList")));
                        model.indexedBranches = new ArrayList<String>(Arrays.asList(config.getStringList(
                                        Constants.CONFIG_GITBLIT, null, "indexBranch")));
+                       model.metricAuthorExclusions = new ArrayList<String>(Arrays.asList(config.getStringList(
+                                       Constants.CONFIG_GITBLIT, null, "metricAuthorExclusions")));
                        
                        // Custom defined properties
                        model.customFields = new LinkedHashMap<String, String>();
@@ -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) {
index 59405c7f469c170ea647f04f9bf8d41ab73eac5b..547c348fb36aa6c906f975854587f9908a4fdf4e 100644 (file)
@@ -17,6 +17,7 @@ package com.gitblit.models;
 \r
 import java.io.Serializable;\r
 import java.util.ArrayList;\r
+import java.util.Collection;\r
 import java.util.Collections;\r
 import java.util.Date;\r
 import java.util.HashMap;\r
@@ -24,6 +25,7 @@ import java.util.LinkedHashSet;
 import java.util.List;\r
 import java.util.Map;\r
 import java.util.Set;\r
+import java.util.TreeSet;\r
 \r
 import org.eclipse.jgit.revwalk.RevCommit;\r
 \r
@@ -43,13 +45,15 @@ public class Activity implements Serializable, Comparable<Activity> {
        public final Date startDate;\r
 \r
        public final Date endDate;\r
-\r
+       \r
        private final Set<RepositoryCommit> commits;\r
 \r
        private final Map<String, Metric> authorMetrics;\r
 \r
        private final Map<String, Metric> repositoryMetrics;\r
 \r
+       private final Set<String> authorExclusions;\r
+\r
        /**\r
         * Constructor for one day of activity.\r
         * \r
@@ -73,6 +77,18 @@ public class Activity implements Serializable, Comparable<Activity> {
                commits = new LinkedHashSet<RepositoryCommit>();\r
                authorMetrics = new HashMap<String, Metric>();\r
                repositoryMetrics = new HashMap<String, Metric>();\r
+               authorExclusions = new TreeSet<String>();\r
+       }\r
+       \r
+       /**\r
+        * Exclude the specified authors from the metrics.\r
+        * \r
+        * @param authors\r
+        */\r
+       public void excludeAuthors(Collection<String> authors) {\r
+               for (String author : authors) {\r
+                       authorExclusions.add(author.toLowerCase());\r
+               }\r
        }\r
 \r
        /**\r
@@ -88,16 +104,20 @@ public class Activity implements Serializable, Comparable<Activity> {
        public RepositoryCommit addCommit(String repository, String branch, RevCommit commit) {\r
                RepositoryCommit commitModel = new RepositoryCommit(repository, branch, commit);\r
                if (commits.add(commitModel)) {\r
+                       String author = StringUtils.removeNewlines(commit.getAuthorIdent().getName());\r
+                       String authorName = author.toLowerCase();\r
+                       String authorEmail = StringUtils.removeNewlines(commit.getAuthorIdent().getEmailAddress()).toLowerCase();\r
                        if (!repositoryMetrics.containsKey(repository)) {\r
                                repositoryMetrics.put(repository, new Metric(repository));\r
                        }\r
                        repositoryMetrics.get(repository).count++;\r
 \r
-                       String author = StringUtils.removeNewlines(commit.getAuthorIdent().getEmailAddress()).toLowerCase();                    \r
-                       if (!authorMetrics.containsKey(author)) {\r
-                               authorMetrics.put(author, new Metric(author));\r
+                       if (!authorExclusions.contains(authorName) && !authorExclusions.contains(authorEmail)) {\r
+                               if (!authorMetrics.containsKey(author)) {\r
+                                       authorMetrics.put(author, new Metric(author));\r
+                               }\r
+                               authorMetrics.get(author).count++;\r
                        }\r
-                       authorMetrics.get(author).count++;\r
                        return commitModel;\r
                }\r
                return null;\r
index 0e39d91268ed71cfa130fd077848b3f1773f6687..5eb51b4b972cf219747457776c5ac5221bbe1a59 100644 (file)
@@ -81,7 +81,8 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel
        public boolean verifyCommitter;\r
        public String gcThreshold;\r
        public int gcPeriod;\r
-       public int maxActivityCommits;\r
+       public int maxActivityCommits;  \r
+       public List<String> metricAuthorExclusions;\r
        \r
        public transient boolean isCollectingGarbage;\r
        public Date lastGC;\r
index 015e8d3deb5605a0dcb262209386fb27dc47cc71..edeb01ad5e8081f2751d9edfba7ccc53236af9e0 100644 (file)
@@ -27,7 +27,9 @@ import java.util.Date;
 import java.util.HashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
+import java.util.Set;\r
 import java.util.TimeZone;\r
+import java.util.TreeSet;\r
 \r
 import org.eclipse.jgit.lib.Constants;\r
 import org.eclipse.jgit.lib.ObjectId;\r
@@ -35,6 +37,7 @@ import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;\r
 \r
 import com.gitblit.GitBlit;\r
+import com.gitblit.Keys;\r
 import com.gitblit.models.Activity;\r
 import com.gitblit.models.GravatarProfile;\r
 import com.gitblit.models.RefModel;\r
@@ -78,6 +81,15 @@ public class ActivityUtils {
                df.setTimeZone(timezone);\r
                Calendar cal = Calendar.getInstance();\r
                cal.setTimeZone(timezone);\r
+               \r
+               // aggregate author exclusions\r
+               Set<String> authorExclusions = new TreeSet<String>();\r
+               authorExclusions.addAll(GitBlit.getStrings(Keys.web.metricAuthorExclusions));\r
+               for (RepositoryModel model : models) {\r
+                       if (!ArrayUtils.isEmpty(model.metricAuthorExclusions)) {\r
+                               authorExclusions.addAll(model.metricAuthorExclusions);\r
+                       }\r
+               }\r
 \r
                Map<String, Activity> activity = new HashMap<String, Activity>();\r
                for (RepositoryModel model : models) {\r
@@ -124,7 +136,9 @@ public class ActivityUtils {
                                                        cal.set(Calendar.MINUTE, 0);\r
                                                        cal.set(Calendar.SECOND, 0);\r
                                                        cal.set(Calendar.MILLISECOND, 0);\r
-                                                       activity.put(dateStr, new Activity(cal.getTime()));\r
+                                                       Activity a = new Activity(cal.getTime());\r
+                                                       a.excludeAuthors(authorExclusions);\r
+                                                       activity.put(dateStr, a);\r
                                                }\r
                                                RepositoryCommit commitModel = activity.get(dateStr)\r
                                                                .addCommit(model.name, shortName, commit);\r
index 945e08b115c61d52283d6f9406d951ecd45a4552..a9b46670e6d41b1b208590c141ced5293a9981aa 100644 (file)
@@ -16,7 +16,9 @@
 package com.gitblit.wicket.charting;\r
 \r
 import java.text.MessageFormat;\r
+import java.util.ArrayList;\r
 import java.util.Collections;\r
+import java.util.List;\r
 \r
 import com.gitblit.utils.StringUtils;\r
 \r
@@ -44,10 +46,27 @@ public class GooglePieChart extends GoogleChart {
                line(sb, MessageFormat.format("{0}.addRows({1,number,0});", dName, values.size()));\r
 \r
                Collections.sort(values);\r
-\r
-               StringBuilder colors = new StringBuilder("colors:[");\r
-               for (int i = 0; i < values.size(); i++) {\r
+               List<ChartValue> list = new ArrayList<ChartValue>();\r
+               \r
+               int maxSlices = 10;\r
+               int maxCount = Math.min(maxSlices - 1,  values.size());\r
+               \r
+               for (int i = 0; i < maxCount; i++) {\r
                        ChartValue value = values.get(i);\r
+                       list.add(value);\r
+               }\r
+               if (values.size() >= maxSlices) {\r
+                       float others = 0;\r
+                       for (int i = maxSlices - 1; i < values.size(); i++) {\r
+                               others += values.get(i).value;  \r
+                       }\r
+                       ChartValue other = new ChartValue("other", others);\r
+                       list.add(other);\r
+               }\r
+               \r
+               StringBuilder colors = new StringBuilder("colors:[");\r
+               for (int i = 0; i < list.size(); i++) {\r
+                       ChartValue value = list.get(i);\r
                        colors.append('\'');\r
                        colors.append(StringUtils.getColor(value.name));\r
                        colors.append('\'');\r
index 39771aefa83dbe9e634bf71714ce34b954e20f5e..66bbf7347ce28471f61f5af6a81020a03e5c19ba 100644 (file)
@@ -34,6 +34,7 @@ import java.util.List;
 import java.util.Map;\r
 import java.util.Set;\r
 import java.util.TimeZone;\r
+import java.util.TreeSet;\r
 \r
 import org.apache.wicket.Component;\r
 import org.apache.wicket.PageParameters;\r
@@ -187,7 +188,20 @@ public class DashboardPage extends RootPage {
                \r
                // add the nifty charts\r
                if (!ArrayUtils.isEmpty(pushes)) {\r
-                       GoogleCharts charts = createCharts(pushes);\r
+                       // aggregate author exclusions\r
+                       Set<String> authorExclusions = new TreeSet<String>();\r
+                       for (String author : GitBlit.getStrings(Keys.web.metricAuthorExclusions)) {\r
+                               authorExclusions.add(author.toLowerCase());\r
+                       }\r
+                       for (RepositoryModel model : feedSources) {\r
+                               if (!ArrayUtils.isEmpty(model.metricAuthorExclusions)) {\r
+                                       for (String author : model.metricAuthorExclusions) {\r
+                                               authorExclusions.add(author.toLowerCase());\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       GoogleCharts charts = createCharts(pushes, authorExclusions);\r
                        add(new HeaderContributor(charts));\r
                }\r
                \r
@@ -359,7 +373,7 @@ public class DashboardPage extends RootPage {
         * @param recentPushes\r
         * @return\r
         */\r
-       private GoogleCharts createCharts(List<PushLogEntry> recentPushes) {\r
+       private GoogleCharts createCharts(List<PushLogEntry> recentPushes, Set<String> authorExclusions) {\r
                // activity metrics\r
                Map<String, Metric> repositoryMetrics = new HashMap<String, Metric>();\r
                Map<String, Metric> authorMetrics = new HashMap<String, Metric>();\r
@@ -375,11 +389,15 @@ public class DashboardPage extends RootPage {
                        repositoryMetrics.get(repository).count += 1;\r
                        \r
                        for (RepositoryCommit commit : push.getCommits()) {\r
-                               String author = commit.getAuthorIdent().getName();\r
-                               if (!authorMetrics.containsKey(author)) {\r
-                                       authorMetrics.put(author, new Metric(author));\r
+                               String author = StringUtils.removeNewlines(commit.getAuthorIdent().getName());\r
+                               String authorName = author.toLowerCase();\r
+                               String authorEmail = StringUtils.removeNewlines(commit.getAuthorIdent().getEmailAddress()).toLowerCase();\r
+                               if (!authorExclusions.contains(authorName) && !authorExclusions.contains(authorEmail)) {\r
+                                       if (!authorMetrics.containsKey(author)) {\r
+                                               authorMetrics.put(author, new Metric(author));\r
+                                       }\r
+                                       authorMetrics.get(author).count += 1;\r
                                }\r
-                               authorMetrics.get(author).count += 1;\r
                        }\r
                }\r
 \r
index f8ecb992d4aeeb5f0d91c4a583e91752fabf597a..38070273afc1c85a01e94c6eed7005cbfe3e1a53 100644 (file)
@@ -41,8 +41,9 @@
                                <tr><th><wicket:message key="gb.skipSizeCalculation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSizeCalculation" tabindex="11" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSizeCalculationDescription"></wicket:message></span></label></td></tr>\r
                                <tr><th><wicket:message key="gb.skipSummaryMetrics"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSummaryMetrics" tabindex="12" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSummaryMetricsDescription"></wicket:message></span></label></td></tr>\r
                                <tr><th><wicket:message key="gb.maxActivityCommits"></wicket:message></th><td class="edit"><select class="span2" wicket:id="maxActivityCommits" tabindex="13" /> &nbsp;<span class="help-inline"><wicket:message key="gb.maxActivityCommitsDescription"></wicket:message></span></td></tr>\r
+                               <tr><th><wicket:message key="gb.metricAuthorExclusions"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="metricAuthorExclusions" size="40" tabindex="14" /></td></tr>\r
                                <tr><th colspan="2"><hr/></th></tr>\r
-                               <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="14" /></td></tr>\r
+                               <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="15" /></td></tr>\r
                        </tbody>\r
                </table>\r
                </div>\r
                <div class="tab-pane" id="permissions">\r
                        <table class="plain">\r
                                <tbody class="settings">\r
-                                       <tr><th><wicket:message key="gb.owners"></wicket:message></th><td class="edit"><span wicket:id="owners" tabindex="15" /> </td></tr>\r
+                                       <tr><th><wicket:message key="gb.owners"></wicket:message></th><td class="edit"><span wicket:id="owners" tabindex="16" /> </td></tr>\r
                                        <tr><th colspan="2"><hr/></th></tr>\r
-                                       <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="16" /></td></tr>\r
+                                       <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="17" /></td></tr>\r
                                        <tr><th colspan="2"><hr/></th></tr>\r
                                        <tr><th><wicket:message key="gb.authorizationControl"></wicket:message></th><td style="padding:2px;"><span class="authorizationControl" wicket:id="authorizationControl"></span></td></tr>\r
                                        <tr><th colspan="2"><hr/></th></tr>\r
-                                       <tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="isFrozen" tabindex="17" /> &nbsp;<span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></label></td></tr>\r
-                                       <tr><th><wicket:message key="gb.allowForks"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="allowForks" tabindex="18" /> &nbsp;<span class="help-inline"><wicket:message key="gb.allowForksDescription"></wicket:message></span></label></td></tr>\r
-                                       <tr><th><wicket:message key="gb.verifyCommitter"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="verifyCommitter" tabindex="19" /> &nbsp;<span class="help-inline"><wicket:message key="gb.verifyCommitterDescription"></wicket:message></span><br/><span class="help-inline" style="padding-left:10px;"><wicket:message key="gb.verifyCommitterNote"></wicket:message></span></label></td></tr>\r
+                                       <tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="isFrozen" tabindex="18" /> &nbsp;<span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></label></td></tr>\r
+                                       <tr><th><wicket:message key="gb.allowForks"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="allowForks" tabindex="19" /> &nbsp;<span class="help-inline"><wicket:message key="gb.allowForksDescription"></wicket:message></span></label></td></tr>\r
+                                       <tr><th><wicket:message key="gb.verifyCommitter"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="verifyCommitter" tabindex="20" /> &nbsp;<span class="help-inline"><wicket:message key="gb.verifyCommitterDescription"></wicket:message></span><br/><span class="help-inline" style="padding-left:10px;"><wicket:message key="gb.verifyCommitterNote"></wicket:message></span></label></td></tr>\r
                                        <tr><th colspan="2"><hr/></th></tr>\r
                                        <tr><th><wicket:message key="gb.userPermissions"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>\r
                                        <tr><th colspan="2"><hr/></th></tr>\r
@@ -72,7 +73,7 @@
                <div class="tab-pane" id="federation">\r
                        <table class="plain">\r
                                <tbody class="settings">\r
-                                       <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="20" /></td></tr>\r
+                                       <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="21" /></td></tr>\r
                                        <tr><th><wicket:message key="gb.federationSets"></wicket:message></th><td style="padding:2px;"><span wicket:id="federationSets"></span></td></tr>\r
                                </tbody>\r
                        </table>\r
index 938b05e3ef21ba1fa9a7a39a986b934acf8820b7..4c471a1e79265f4e55b2ff892f9730fa9d9dbfcf 100644 (file)
@@ -76,6 +76,8 @@ public class EditRepositoryPage extends RootSubPage {
        \r
        RepositoryModel repositoryModel;\r
 \r
+       private IModel<String> metricAuthorExclusions;\r
+       \r
        private IModel<String> mailingLists;\r
 \r
        public EditRepositoryPage() {\r
@@ -316,6 +318,23 @@ public class EditRepositoryPage extends RootSubPage {
                                                }\r
                                        }\r
 \r
+                                       // set author metric exclusions\r
+                                       String ax = metricAuthorExclusions.getObject();\r
+                                       if (!StringUtils.isEmpty(ax)) {\r
+                                               Set<String> list = new HashSet<String>();\r
+                                               for (String exclusion : StringUtils.getStringsFromValue(ax,  " ")) {\r
+                                                       if (StringUtils.isEmpty(exclusion)) {\r
+                                                               continue;\r
+                                                       }\r
+                                                       if (exclusion.indexOf(' ') > -1) {\r
+                                                               list.add("\"" + exclusion + "\"");      \r
+                                                       } else {\r
+                                                               list.add(exclusion);\r
+                                                       }\r
+                                               }\r
+                                               repositoryModel.metricAuthorExclusions = new ArrayList<String>(list);\r
+                                       }\r
+\r
                                        // set mailing lists\r
                                        String ml = mailingLists.getObject();\r
                                        if (!StringUtils.isEmpty(ml)) {\r
@@ -435,6 +454,10 @@ public class EditRepositoryPage extends RootSubPage {
                List<Integer> maxActivityCommits  = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500 );\r
                form.add(new DropDownChoice<Integer>("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer()));\r
 \r
+               metricAuthorExclusions = new Model<String>(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? ""\r
+                               : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " "));\r
+               form.add(new TextField<String>("metricAuthorExclusions", metricAuthorExclusions));\r
+\r
                mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""\r
                                : StringUtils.flattenStrings(repositoryModel.mailingLists, " "));\r
                form.add(new TextField<String>("mailingLists", mailingLists));\r