James Moger
2013-06-10 cedf138f3c9afeae7bcbda5dbb0511ebec297d10
Globl and per-repository setting to exclude authors form metrics (issue-251)
10 files modified
154 ■■■■ changed files
releases.moxie 2 ●●●●● patch | view | raw | blame | history
src/main/distrib/data/gitblit.properties 7 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/GitBlit.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/models/Activity.java 30 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/models/RepositoryModel.java 3 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/utils/ActivityUtils.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/charting/GooglePieChart.java 25 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/DashboardPage.java 30 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html 15 ●●●● patch | view | raw | blame | history
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java 23 ●●●●● patch | view | raw | blame | history
releases.moxie
@@ -42,6 +42,7 @@
     - 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 @@
    - { 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 }
src/main/distrib/data/gitblit.properties
@@ -826,6 +826,13 @@
# 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
#
src/main/java/com/gitblit/GitBlit.java
@@ -1939,6 +1939,8 @@
                    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 @@
        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) {
src/main/java/com/gitblit/models/Activity.java
@@ -17,6 +17,7 @@
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.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -43,12 +45,14 @@
    public final Date startDate;
    public final Date endDate;
    private final Set<RepositoryCommit> commits;
    private final Map<String, Metric> authorMetrics;
    private final Map<String, Metric> repositoryMetrics;
    private final Set<String> authorExclusions;
    /**
     * Constructor for one day of activity.
@@ -73,6 +77,18 @@
        commits = new LinkedHashSet<RepositoryCommit>();
        authorMetrics = new HashMap<String, Metric>();
        repositoryMetrics = new HashMap<String, Metric>();
        authorExclusions = new TreeSet<String>();
    }
    /**
     * Exclude the specified authors from the metrics.
     *
     * @param authors
     */
    public void excludeAuthors(Collection<String> authors) {
        for (String author : authors) {
            authorExclusions.add(author.toLowerCase());
        }
    }
    /**
@@ -88,16 +104,20 @@
    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;
src/main/java/com/gitblit/models/RepositoryModel.java
@@ -81,7 +81,8 @@
    public boolean verifyCommitter;
    public String gcThreshold;
    public int gcPeriod;
    public int maxActivityCommits;
    public int maxActivityCommits;
    public List<String> metricAuthorExclusions;
    
    public transient boolean isCollectingGarbage;
    public Date lastGC;
src/main/java/com/gitblit/utils/ActivityUtils.java
@@ -27,7 +27,9 @@
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.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 @@
        df.setTimeZone(timezone);
        Calendar cal = Calendar.getInstance();
        cal.setTimeZone(timezone);
        // aggregate author exclusions
        Set<String> authorExclusions = new TreeSet<String>();
        authorExclusions.addAll(GitBlit.getStrings(Keys.web.metricAuthorExclusions));
        for (RepositoryModel model : models) {
            if (!ArrayUtils.isEmpty(model.metricAuthorExclusions)) {
                authorExclusions.addAll(model.metricAuthorExclusions);
            }
        }
        Map<String, Activity> activity = new HashMap<String, Activity>();
        for (RepositoryModel model : models) {
@@ -124,7 +136,9 @@
                            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);
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 @@
        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<ChartValue> list = new ArrayList<ChartValue>();
        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('\'');
src/main/java/com/gitblit/wicket/pages/DashboardPage.java
@@ -34,6 +34,7 @@
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 @@
        
        // add the nifty charts
        if (!ArrayUtils.isEmpty(pushes)) {
            GoogleCharts charts = createCharts(pushes);
            // aggregate author exclusions
            Set<String> authorExclusions = new TreeSet<String>();
            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 @@
     * @param recentPushes
     * @return
     */
    private GoogleCharts createCharts(List<PushLogEntry> recentPushes) {
    private GoogleCharts createCharts(List<PushLogEntry> recentPushes, Set<String> authorExclusions) {
        // activity metrics
        Map<String, Metric> repositoryMetrics = new HashMap<String, Metric>();
        Map<String, Metric> authorMetrics = new HashMap<String, Metric>();
@@ -375,11 +389,15 @@
            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;
            }
        }
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html
@@ -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>
                <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>
                <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>
                <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>
                <tr><th colspan="2"><hr/></th></tr>
                <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>
                <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>
            </tbody>
        </table>
        </div>
@@ -51,15 +52,15 @@
        <div class="tab-pane" id="permissions">
            <table class="plain">
                <tbody class="settings">
                    <tr><th><wicket:message key="gb.owners"></wicket:message></th><td class="edit"><span wicket:id="owners" tabindex="15" /> </td></tr>
                    <tr><th><wicket:message key="gb.owners"></wicket:message></th><td class="edit"><span wicket:id="owners" tabindex="16" /> </td></tr>
                    <tr><th colspan="2"><hr/></th></tr>
                    <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="16" /></td></tr>
                    <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="17" /></td></tr>
                    <tr><th colspan="2"><hr/></th></tr>
                    <tr><th><wicket:message key="gb.authorizationControl"></wicket:message></th><td style="padding:2px;"><span class="authorizationControl" wicket:id="authorizationControl"></span></td></tr>
                    <tr><th colspan="2"><hr/></th></tr>
                    <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>
                    <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>
                    <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>
                    <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>
                    <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>
                    <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>
                    <tr><th colspan="2"><hr/></th></tr>
                    <tr><th><wicket:message key="gb.userPermissions"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>
                    <tr><th colspan="2"><hr/></th></tr>
@@ -72,7 +73,7 @@
        <div class="tab-pane" id="federation">
            <table class="plain">
                <tbody class="settings">
                    <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="20" /></td></tr>
                    <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="21" /></td></tr>
                    <tr><th><wicket:message key="gb.federationSets"></wicket:message></th><td style="padding:2px;"><span wicket:id="federationSets"></span></td></tr>
                </tbody>
            </table>
src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -76,6 +76,8 @@
    
    RepositoryModel repositoryModel;
    private IModel<String> metricAuthorExclusions;
    private IModel<String> mailingLists;
    public EditRepositoryPage() {
@@ -316,6 +318,23 @@
                        }
                    }
                    // set author metric exclusions
                    String ax = metricAuthorExclusions.getObject();
                    if (!StringUtils.isEmpty(ax)) {
                        Set<String> list = new HashSet<String>();
                        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<String>(list);
                    }
                    // set mailing lists
                    String ml = mailingLists.getObject();
                    if (!StringUtils.isEmpty(ml)) {
@@ -435,6 +454,10 @@
        List<Integer> maxActivityCommits  = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500 );
        form.add(new DropDownChoice<Integer>("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer()));
        metricAuthorExclusions = new Model<String>(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? ""
                : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " "));
        form.add(new TextField<String>("metricAuthorExclusions", metricAuthorExclusions));
        mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
                : StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
        form.add(new TextField<String>("mailingLists", mailingLists));