Browse Source

Tag diamonds and sliding date scale on activity graph.

tags/v0.5.0
James Moger 13 years ago
parent
commit
45c0d6ed8c

+ 6
- 1
contrib/com/codecommit/wicket/LineStyle.java View File

@@ -3,10 +3,15 @@
*/
package com.codecommit.wicket;
import java.io.Serializable;
/**
* @author Daniel Spiewak
*/
public class LineStyle implements ILineStyle {
public class LineStyle implements ILineStyle, Serializable {
private static final long serialVersionUID = 1L;
private int blankLength = -1;
private int segmentLength = -1;
private int thickness = -1;

+ 3
- 1
contrib/com/codecommit/wicket/MarkerType.java View File

@@ -3,10 +3,12 @@
*/
package com.codecommit.wicket;
import java.io.Serializable;
/**
* @author Daniel Spiewak
*/
public enum MarkerType {
public enum MarkerType implements Serializable {
ARROW("a"),
CROSS("c"),
DIAMOND("d"),

+ 5
- 1
contrib/com/codecommit/wicket/ShapeMarker.java View File

@@ -4,11 +4,15 @@
package com.codecommit.wicket;
import java.awt.Color;
import java.io.Serializable;
/**
* @author Daniel Spiewak
*/
public class ShapeMarker implements IShapeMarker {
public class ShapeMarker implements IShapeMarker, Serializable {
private static final long serialVersionUID = 1L;
private Color color;
private int index = -1;
private double point = -1;

+ 3
- 3
gitblit.properties View File

@@ -65,7 +65,7 @@ web.generateActivityGraph = true
# The number of commits to display on the summary page
# Value must exceed 0 else default of 20 is used
web.summaryCommitCount = 20
web.summaryCommitCount = 16
# The number of tags/heads to display on the summary page
# Value must exceed 0 else default of 5 is used
@@ -130,11 +130,11 @@ server.httpsPort = 443
# Specify the interface for Jetty to bind the standard connector.
# You may specify an ip or an empty value to bind to all interfaces.
server.httpBindInterface =
server.httpBindInterface = localhost
# Specify the interface for Jetty to bind the secure connector.
# You may specify an ip or an empty value to bind to all interfaces.
server.httpsBindInterface =
server.httpsBindInterface = localhost
# Password for SSL keystore (keystore password and certificate password must match)
server.storePassword = dosomegit

+ 8
- 0
src/com/gitblit/tests/JGitUtilsTest.java View File

@@ -50,6 +50,14 @@ public class JGitUtilsTest extends TestCase {
r.close();
assertTrue("Could not get last repository change date!", date != null);
}
public void testFirstCommit() throws Exception {
Repository r = getRepository();
RevCommit commit = JGitUtils.getFirstCommit(r, null);
r.close();
assertTrue("Could not get first commit!", commit != null);
System.out.println(commit.getName() + " " + commit.getShortMessage());
}
public void testRetrieveRevObject() throws Exception {
Repository r = getRepository();

+ 68
- 11
src/com/gitblit/utils/JGitUtils.java View File

@@ -36,6 +36,7 @@ import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.RevFilter;
@@ -101,6 +102,34 @@ public class JGitUtils {
return list;
}
public static RevCommit getFirstCommit(Repository r, String branch) {
if (StringUtils.isEmpty(branch)) {
branch = Constants.HEAD;
}
try {
RevWalk walk = new RevWalk(r);
walk.sort(RevSort.REVERSE);
RevCommit head = walk.parseCommit(r.resolve(branch));
walk.markStart(head);
RevCommit commit = walk.next();
walk.dispose();
return commit;
} catch (Throwable t) {
LOGGER.error("Failed to determine first commit", t);
}
return null;
}
public static Date getFirstChange(Repository r, String branch) {
try {
RevCommit commit = getFirstCommit(r, branch);
return getCommitDate(commit);
} catch (Throwable t) {
LOGGER.error("Failed to determine first change", t);
}
return null;
}
public static Date getLastChange(Repository r) {
RevCommit commit = getCommit(r, Constants.HEAD);
return getCommitDate(commit);
@@ -525,7 +554,7 @@ public class JGitUtils {
}
return null;
}
public String toString() {
return name().toLowerCase();
}
@@ -552,7 +581,7 @@ public class JGitUtils {
case AUTHOR:
return (commit.getAuthorIdent().getName().toLowerCase().indexOf(lcValue) > -1) || (commit.getAuthorIdent().getEmailAddress().toLowerCase().indexOf(lcValue) > -1);
case COMMITTER:
return (commit.getCommitterIdent().getName().toLowerCase().indexOf(lcValue) > -1)|| (commit.getCommitterIdent().getEmailAddress().toLowerCase().indexOf(lcValue) > -1);
return (commit.getCommitterIdent().getName().toLowerCase().indexOf(lcValue) > -1) || (commit.getCommitterIdent().getEmailAddress().toLowerCase().indexOf(lcValue) > -1);
case COMMIT:
return commit.getFullMessage().toLowerCase().indexOf(lcValue) > -1;
}
@@ -695,29 +724,57 @@ public class JGitUtils {
public static List<Metric> getDateMetrics(Repository r) {
final List<RefModel> tags = getTags(r, -1);
final Map<String, Metric> map = new HashMap<String, Metric>();
final Map<ObjectId, RefModel> tagMap = new HashMap<ObjectId, RefModel>();
for (RefModel tag : tags) {
tagMap.put(tag.getCommitId(), tag);
}
Metric total = new Metric("TOTAL");
final Map<String, Metric> metricMap = new HashMap<String, Metric>();
try {
DateFormat df = new SimpleDateFormat("yyyy-MM");
RevWalk walk = new RevWalk(r);
ObjectId object = r.resolve(Constants.HEAD);
walk.markStart(walk.parseCommit(object));
RevCommit firstCommit = getFirstCommit(r, Constants.HEAD);
RevCommit lastCommit = walk.parseCommit(object);
int diffDays = (lastCommit.getCommitTime() - firstCommit.getCommitTime()) / (60 * 60 * 24);
total.duration = diffDays;
DateFormat df;
if (diffDays <= 90) {
// Days
df = new SimpleDateFormat("yyyy-MM-dd");
} else if (diffDays > 90 && diffDays < 365) {
// Weeks
df = new SimpleDateFormat("yyyy-MM (w)");
} else {
// Months
df = new SimpleDateFormat("yyyy-MM");
}
walk.markStart(lastCommit);
Iterable<RevCommit> revlog = walk;
for (RevCommit rev : revlog) {
Date d = getCommitDate(rev);
String p = df.format(d);
if (!map.containsKey(p))
map.put(p, new Metric(p));
map.get(p).count++;
}
if (!metricMap.containsKey(p))
metricMap.put(p, new Metric(p));
Metric m = metricMap.get(p);
m.count++;
total.count++;
if (tagMap.containsKey(rev.getId())) {
m.tag++;
total.tag++;
}
}
} catch (Throwable t) {
LOGGER.error("Failed to mine log history for metrics", t);
}
List<String> keys = new ArrayList<String>(map.keySet());
List<String> keys = new ArrayList<String>(metricMap.keySet());
Collections.sort(keys);
List<Metric> metrics = new ArrayList<Metric>();
for (String key : keys) {
metrics.add(map.get(key));
metrics.add(metricMap.get(key));
}
metrics.add(0, total);
return metrics;
}

+ 34
- 0
src/com/gitblit/utils/TimeUtils.java View File

@@ -23,6 +23,40 @@ public class TimeUtils {
return now.getDate() == (date.getDate() + 1) && now.getMonth() == date.getMonth() && now.getYear() == date.getYear();
}
public static String duration(int days) {
if (days <= 60) {
return days + (days > 1 ? " days" : " day");
} else if (days <= 365) {
int rem = days % 30;
return (days / 30) + " months, " + rem + (rem > 1 ? " days" : " day");
} else {
int years = days / 365;
int rem = days % 365;
String yearsString = years + (years > 1 ? " years" : " year");
if (rem < 30) {
if (rem == 0) {
return yearsString;
} else {
return yearsString + ", " + rem + (rem > 1 ? " days" : " day");
}
} else {
int months = rem / 30;
int remDays = (rem % 30);
String monthsString;
if (months == 0) {
monthsString = yearsString;
} else {
monthsString = yearsString + ", " + months + (months > 1 ? " months" : " month");
}
if (remDays == 0) {
return monthsString;
} else {
return monthsString + ", " + remDays + (remDays > 1 ? " days":" day");
}
}
}
}
public static int minutesAgo(Date date, long endTime, boolean roundup) {
long diff = endTime - date.getTime();
int mins = (int) (diff / min);

+ 2
- 1
src/com/gitblit/wicket/GitBlitWebApp.properties View File

@@ -54,4 +54,5 @@ gb.searchForCommitter = Search for commits committed by
gb.addition = addition
gb.modification = modification
gb.deletion = deletion
gb.rename = rename
gb.rename = rename
gb.stats = stats

+ 2
- 0
src/com/gitblit/wicket/models/Metric.java View File

@@ -8,6 +8,8 @@ public class Metric implements Serializable {
public String name;
public double count;
public double tag;
public int duration;
public Metric(String name) {
this.name = name;

+ 7
- 6
src/com/gitblit/wicket/pages/SummaryPage.html View File

@@ -12,17 +12,18 @@
<div style="clear:both;">
<!-- Repository Activity Chart -->
<div style="width:400px;float:right;">
<div style="float:right;">
<img class="activityGraph" wicket:id="commitsChart" />
</div>
<!-- Repository info -->
<div style="margin-right:410px;">
<div>
<table class="plain">
<tr><th><wicket:message key="gb.description">description</wicket:message></th><td><span wicket:id="repositoryDescription">[repository description]</span></td></tr>
<tr><th><wicket:message key="gb.owner">owner</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>
<tr><th><wicket:message key="gb.lastChange">last change</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>
<tr><th><wicket:message key="gb.url">URL</wicket:message></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>
<tr><th><wicket:message key="gb.description">[description]</wicket:message></th><td><span wicket:id="repositoryDescription">[repository description]</span></td></tr>
<tr><th><wicket:message key="gb.owner">[owner]</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>
<tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>
<tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="repositoryStats">[repository stats]</span></td></tr>
<tr><th><wicket:message key="gb.url">[URL]</wicket:message></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>
</table>
</div>
</div>

+ 31
- 15
src/com/gitblit/wicket/pages/SummaryPage.java View File

@@ -1,6 +1,8 @@
package com.gitblit.wicket.pages;
import java.awt.Color;
import java.awt.Dimension;
import java.text.MessageFormat;
import java.util.List;
import org.apache.wicket.PageParameters;
@@ -15,9 +17,13 @@ import com.codecommit.wicket.ChartAxisType;
import com.codecommit.wicket.ChartProvider;
import com.codecommit.wicket.ChartType;
import com.codecommit.wicket.IChartData;
import com.codecommit.wicket.LineStyle;
import com.codecommit.wicket.MarkerType;
import com.codecommit.wicket.ShapeMarker;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.TimeUtils;
import com.gitblit.wicket.RepositoryPage;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.models.Metric;
@@ -44,11 +50,11 @@ public class SummaryPage extends RepositoryPage {
}
Repository r = getRepository();
List<Metric> metrics = JGitUtils.getDateMetrics(r);
long numberOfCommits = 0;
for (Metric m : metrics) {
numberOfCommits += m.count;
List<Metric> metrics = null;
Metric metricsTotal = null;
if (GitBlit.self().settings().getBoolean(Keys.web.generateActivityGraph, true)) {
metrics = JGitUtils.getDateMetrics(r);
metricsTotal = metrics.remove(0);
}
// repository description
@@ -56,6 +62,11 @@ public class SummaryPage extends RepositoryPage {
add(new Label("repositoryOwner", JGitUtils.getRepositoryOwner(r)));
add(WicketUtils.createTimestampLabel("repositoryLastChange", JGitUtils.getLastChange(r), getTimeZone()));
if (metricsTotal == null) {
add(new Label("repositoryStats", ""));
} else {
add(new Label("repositoryStats", MessageFormat.format("{0} commits and {1} tags in {2}", metricsTotal.count, metricsTotal.tag, TimeUtils.duration(metricsTotal.duration))));
}
add(new Label("repositoryCloneUrl", GitBlit.self().getCloneUrl(repositoryName)));
add(new LogPanel("commitsPanel", repositoryName, null, r, numberCommits, 0));
@@ -75,7 +86,7 @@ public class SummaryPage extends RepositoryPage {
if (GitBlit.self().settings().getBoolean(Keys.web.generateActivityGraph, true)) {
IChartData data = getChartData(metrics);
ChartProvider provider = new ChartProvider(new Dimension(400, 80), ChartType.LINE, data);
ChartProvider provider = new ChartProvider(new Dimension(400, 100), ChartType.LINE, data);
ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);
dateAxis.setLabels(new String[] { metrics.get(0).name, metrics.get(metrics.size() / 2).name, metrics.get(metrics.size() - 1).name });
provider.addAxis(dateAxis);
@@ -84,6 +95,9 @@ public class SummaryPage extends RepositoryPage {
commitAxis.setLabels(new String[] { "", String.valueOf((int) maxValue(metrics)) });
provider.addAxis(commitAxis);
provider.setLineStyles(new LineStyle[] {new LineStyle(2, 4, 0), new LineStyle(0, 4, 1)});
provider.addShapeMarker(new ShapeMarker(MarkerType.DIAMOND, Color.BLUE, 1, -1, 5));
add(new Chart("commitsChart", provider));
} else {
add(new ContextImage("commitsChart", "blank.png"));
@@ -91,23 +105,25 @@ public class SummaryPage extends RepositoryPage {
}
protected IChartData getChartData(List<Metric> metrics) {
final double[] counts = new double[metrics.size()];
final double[] commits = new double[metrics.size()];
final double[] tags = new double[metrics.size()];
int i = 0;
double max = 0;
for (Metric m : metrics) {
counts[i++] = m.count;
commits[i] = m.count;
if (m.tag > 0) {
tags[i] = m.count;
} else {
tags[i] = -1d;
}
max = Math.max(max, m.count);
i++;
}
final double dmax = max;
IChartData data = new AbstractChartData() {
IChartData data = new AbstractChartData(max) {
private static final long serialVersionUID = 1L;
public double[][] getData() {
return new double[][] { counts };
}
public double getMax() {
return dmax;
return new double[][] { commits, tags };
}
};
return data;

Loading…
Cancel
Save