]> source.dussan.org Git - gitblit.git/commitdiff
Tag diamonds and sliding date scale on activity graph.
authorJames Moger <james.moger@gitblit.com>
Wed, 20 Apr 2011 11:53:15 +0000 (07:53 -0400)
committerJames Moger <james.moger@gitblit.com>
Wed, 20 Apr 2011 11:53:15 +0000 (07:53 -0400)
contrib/com/codecommit/wicket/LineStyle.java
contrib/com/codecommit/wicket/MarkerType.java
contrib/com/codecommit/wicket/ShapeMarker.java
gitblit.properties
src/com/gitblit/tests/JGitUtilsTest.java
src/com/gitblit/utils/JGitUtils.java
src/com/gitblit/utils/TimeUtils.java
src/com/gitblit/wicket/GitBlitWebApp.properties
src/com/gitblit/wicket/models/Metric.java
src/com/gitblit/wicket/pages/SummaryPage.html
src/com/gitblit/wicket/pages/SummaryPage.java

index 0b1eade7865cb2f6cb8bea0f8315f484d3156fb9..ef53c5b7ddfde3834f5ec20b891e68d073d3198c 100644 (file)
@@ -3,10 +3,15 @@
  */\r
 package com.codecommit.wicket;\r
 \r
+import java.io.Serializable;\r
+\r
 /**\r
  * @author Daniel Spiewak\r
  */\r
-public class LineStyle implements ILineStyle {\r
+public class LineStyle implements ILineStyle, Serializable {\r
+\r
+       private static final long serialVersionUID = 1L;\r
+       \r
        private int blankLength = -1;\r
        private int segmentLength = -1;\r
        private int thickness = -1;\r
index d14ff543de3a948429b548e982819d95f0e37b2d..2b2279494e6e0c37259047f2d641f8e4420819e1 100644 (file)
@@ -3,10 +3,12 @@
  */\r
 package com.codecommit.wicket;\r
 \r
+import java.io.Serializable;\r
+\r
 /**\r
  * @author Daniel Spiewak\r
  */\r
-public enum MarkerType {\r
+public enum MarkerType implements Serializable {\r
        ARROW("a"),\r
        CROSS("c"),\r
        DIAMOND("d"),\r
index 88d1aa14c1b962ec0ea64e7eda8ad451258f669e..3b42cfb20189149fc8781016411179a48e65fc3b 100644 (file)
@@ -4,11 +4,15 @@
 package com.codecommit.wicket;\r
 \r
 import java.awt.Color;\r
+import java.io.Serializable;\r
 \r
 /**\r
  * @author Daniel Spiewak\r
  */\r
-public class ShapeMarker implements IShapeMarker {\r
+public class ShapeMarker implements IShapeMarker, Serializable {\r
+       \r
+       private static final long serialVersionUID = 1L;\r
+       \r
        private Color color;\r
        private int index = -1;\r
        private double point = -1;\r
index a81e5f618a7bca77e70f791df3bc308f7527e237..27a9fff9c3bd54598d0eaa0cff748241d14cb021 100644 (file)
@@ -65,7 +65,7 @@ web.generateActivityGraph = true
 \r
 # The number of commits to display on the summary page\r
 # Value must exceed 0 else default of 20 is used\r
-web.summaryCommitCount = 20\r
+web.summaryCommitCount = 16\r
 \r
 # The number of tags/heads to display on the summary page\r
 # Value must exceed 0 else default of 5 is used\r
@@ -130,11 +130,11 @@ server.httpsPort = 443
 \r
 # Specify the interface for Jetty to bind the standard connector.\r
 # You may specify an ip or an empty value to bind to all interfaces. \r
-server.httpBindInterface = \r
+server.httpBindInterface = localhost\r
 \r
 # Specify the interface for Jetty to bind the secure connector.\r
 # You may specify an ip or an empty value to bind to all interfaces.\r
-server.httpsBindInterface = \r
+server.httpsBindInterface = localhost\r
 \r
 # Password for SSL keystore (keystore password and certificate password must match)\r
 server.storePassword = dosomegit\r
index 0ebcd71e34c67572138afa658d210760ad7163ad..f3c798f1dbeb17f88e85d414984b191b068f7349 100644 (file)
@@ -50,6 +50,14 @@ public class JGitUtilsTest extends TestCase {
                r.close();\r
                assertTrue("Could not get last repository change date!", date != null);\r
        }\r
+       \r
+       public void testFirstCommit() throws Exception {\r
+               Repository r = getRepository();\r
+               RevCommit commit = JGitUtils.getFirstCommit(r, null);\r
+               r.close();\r
+               assertTrue("Could not get first commit!", commit != null);\r
+               System.out.println(commit.getName() + " " + commit.getShortMessage());\r
+       }\r
 \r
        public void testRetrieveRevObject() throws Exception {\r
                Repository r = getRepository();\r
index b1267685ed83e0249d2c8876b5ae296788582028..daeb63896f9dd09b62287342a3666b3cc442c72d 100644 (file)
@@ -36,6 +36,7 @@ import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevBlob;\r
 import org.eclipse.jgit.revwalk.RevCommit;\r
 import org.eclipse.jgit.revwalk.RevObject;\r
+import org.eclipse.jgit.revwalk.RevSort;\r
 import org.eclipse.jgit.revwalk.RevTree;\r
 import org.eclipse.jgit.revwalk.RevWalk;\r
 import org.eclipse.jgit.revwalk.filter.RevFilter;\r
@@ -101,6 +102,34 @@ public class JGitUtils {
                return list;\r
        }\r
 \r
+       public static RevCommit getFirstCommit(Repository r, String branch) {\r
+               if (StringUtils.isEmpty(branch)) {\r
+                       branch = Constants.HEAD;\r
+               }\r
+               try {\r
+                       RevWalk walk = new RevWalk(r);\r
+                       walk.sort(RevSort.REVERSE);\r
+                       RevCommit head = walk.parseCommit(r.resolve(branch));\r
+                       walk.markStart(head);\r
+                       RevCommit commit = walk.next();\r
+                       walk.dispose();\r
+                       return commit;\r
+               } catch (Throwable t) {\r
+                       LOGGER.error("Failed to determine first commit", t);\r
+               }\r
+               return null;\r
+       }\r
+\r
+       public static Date getFirstChange(Repository r, String branch) {\r
+               try {\r
+                       RevCommit commit = getFirstCommit(r, branch);\r
+                       return getCommitDate(commit);\r
+               } catch (Throwable t) {\r
+                       LOGGER.error("Failed to determine first change", t);\r
+               }\r
+               return null;\r
+       }\r
+\r
        public static Date getLastChange(Repository r) {\r
                RevCommit commit = getCommit(r, Constants.HEAD);\r
                return getCommitDate(commit);\r
@@ -525,7 +554,7 @@ public class JGitUtils {
                        }\r
                        return null;\r
                }\r
-               \r
+\r
                public String toString() {\r
                        return name().toLowerCase();\r
                }\r
@@ -552,7 +581,7 @@ public class JGitUtils {
                                        case AUTHOR:\r
                                                return (commit.getAuthorIdent().getName().toLowerCase().indexOf(lcValue) > -1) || (commit.getAuthorIdent().getEmailAddress().toLowerCase().indexOf(lcValue) > -1);\r
                                        case COMMITTER:\r
-                                               return (commit.getCommitterIdent().getName().toLowerCase().indexOf(lcValue) > -1)|| (commit.getCommitterIdent().getEmailAddress().toLowerCase().indexOf(lcValue) > -1);\r
+                                               return (commit.getCommitterIdent().getName().toLowerCase().indexOf(lcValue) > -1) || (commit.getCommitterIdent().getEmailAddress().toLowerCase().indexOf(lcValue) > -1);\r
                                        case COMMIT:\r
                                                return commit.getFullMessage().toLowerCase().indexOf(lcValue) > -1;\r
                                        }\r
@@ -695,29 +724,57 @@ public class JGitUtils {
 \r
        public static List<Metric> getDateMetrics(Repository r) {\r
                final List<RefModel> tags = getTags(r, -1);\r
-               final Map<String, Metric> map = new HashMap<String, Metric>();\r
+               final Map<ObjectId, RefModel> tagMap = new HashMap<ObjectId, RefModel>();\r
+               for (RefModel tag : tags) {\r
+                       tagMap.put(tag.getCommitId(), tag);\r
+               }\r
+               Metric total = new Metric("TOTAL");\r
+               final Map<String, Metric> metricMap = new HashMap<String, Metric>();\r
                try {\r
-                       DateFormat df = new SimpleDateFormat("yyyy-MM");\r
                        RevWalk walk = new RevWalk(r);\r
                        ObjectId object = r.resolve(Constants.HEAD);\r
-                       walk.markStart(walk.parseCommit(object));\r
+\r
+                       RevCommit firstCommit = getFirstCommit(r, Constants.HEAD);\r
+                       RevCommit lastCommit = walk.parseCommit(object);\r
+                       int diffDays = (lastCommit.getCommitTime() - firstCommit.getCommitTime()) / (60 * 60 * 24);\r
+                       total.duration = diffDays;\r
+                       DateFormat df;\r
+                       if (diffDays <= 90) {\r
+                               // Days\r
+                               df = new SimpleDateFormat("yyyy-MM-dd");\r
+                       } else if (diffDays > 90 && diffDays < 365) {\r
+                               // Weeks\r
+                               df = new SimpleDateFormat("yyyy-MM (w)");\r
+                       } else {\r
+                               // Months\r
+                               df = new SimpleDateFormat("yyyy-MM");\r
+                       }\r
+                       walk.markStart(lastCommit);\r
+                       \r
                        Iterable<RevCommit> revlog = walk;\r
                        for (RevCommit rev : revlog) {\r
                                Date d = getCommitDate(rev);\r
                                String p = df.format(d);\r
-                               if (!map.containsKey(p))\r
-                                       map.put(p, new Metric(p));\r
-                               map.get(p).count++;\r
-                       }\r
+                               if (!metricMap.containsKey(p))\r
+                                       metricMap.put(p, new Metric(p));\r
+                               Metric m = metricMap.get(p); \r
+                               m.count++;\r
+                               total.count++;\r
+                               if (tagMap.containsKey(rev.getId())) {\r
+                                       m.tag++;\r
+                                       total.tag++;\r
+                               }\r
+                       }                       \r
                } catch (Throwable t) {\r
                        LOGGER.error("Failed to mine log history for metrics", t);\r
                }\r
-               List<String> keys = new ArrayList<String>(map.keySet());\r
+               List<String> keys = new ArrayList<String>(metricMap.keySet());\r
                Collections.sort(keys);\r
                List<Metric> metrics = new ArrayList<Metric>();\r
                for (String key : keys) {\r
-                       metrics.add(map.get(key));\r
+                       metrics.add(metricMap.get(key));\r
                }\r
+               metrics.add(0, total);\r
                return metrics;\r
        }\r
 \r
index 60b525b7962d579ad2a734c89fed8625cbf1973c..c4e5b59377aa0136479687ca196e3d3ed9caf6b4 100644 (file)
@@ -23,6 +23,40 @@ public class TimeUtils {
                return now.getDate() == (date.getDate() + 1) && now.getMonth() == date.getMonth() && now.getYear() == date.getYear();\r
        }\r
 \r
+       public static String duration(int days) {\r
+               if (days <= 60) {\r
+                       return days + (days > 1 ? " days" : " day");\r
+               } else if (days <= 365) {\r
+                       int rem = days % 30;\r
+                       return (days / 30) + " months, " + rem + (rem > 1 ? " days" : " day");\r
+               } else {\r
+                       int years = days / 365;\r
+                       int rem = days % 365;\r
+                       String yearsString = years + (years > 1 ? " years" : " year");\r
+                       if (rem < 30) {\r
+                               if (rem == 0) {\r
+                                       return yearsString;\r
+                               } else {\r
+                                       return yearsString + ", " + rem + (rem > 1 ? " days" : " day");\r
+                               }\r
+                       } else {\r
+                               int months = rem / 30;\r
+                               int remDays = (rem % 30);\r
+                               String monthsString;\r
+                               if (months == 0) {\r
+                                       monthsString = yearsString;\r
+                               } else {\r
+                                       monthsString = yearsString + ", " + months + (months > 1 ? " months" : " month");\r
+                               }\r
+                               if (remDays == 0) {\r
+                                       return  monthsString;\r
+                               } else {\r
+                                       return monthsString + ", " + remDays + (remDays > 1 ? " days":" day");\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
        public static int minutesAgo(Date date, long endTime, boolean roundup) {\r
                long diff = endTime - date.getTime();\r
                int mins = (int) (diff / min);\r
index b8d31ae578b1ecbcde854d410eeb4f297e709a37..f063858692bbfadd4849646cbd18c99bd22da60c 100644 (file)
@@ -54,4 +54,5 @@ gb.searchForCommitter = Search for commits committed by
 gb.addition = addition\r
 gb.modification = modification\r
 gb.deletion = deletion\r
-gb.rename = rename
\ No newline at end of file
+gb.rename = rename\r
+gb.stats = stats
\ No newline at end of file
index a5efb1397ac915b8f8e5433951151d1c6c8c5648..194e265955f7a1c45919311f1d33f65c9cd3b1a9 100644 (file)
@@ -8,6 +8,8 @@ public class Metric implements Serializable {
 \r
        public String name;\r
        public double count;\r
+       public double tag;\r
+       public int duration;\r
 \r
        public Metric(String name) {\r
                this.name = name;\r
index 47c10b317d0c8ed24c12d366ffd8044f459d4c13..6abef54867fec416854a0ff6596404d41770e573 100644 (file)
        \r
        <div style="clear:both;">\r
                <!-- Repository Activity Chart -->      \r
-               <div style="width:400px;float:right;">\r
+               <div style="float:right;">\r
                        <img class="activityGraph" wicket:id="commitsChart" />\r
                </div>  \r
        \r
                <!-- Repository info -->\r
-               <div style="margin-right:410px;"\r
+               <div> \r
                        <table class="plain">\r
-                               <tr><th><wicket:message key="gb.description">description</wicket:message></th><td><span wicket:id="repositoryDescription">[repository description]</span></td></tr>\r
-                               <tr><th><wicket:message key="gb.owner">owner</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>\r
-                               <tr><th><wicket:message key="gb.lastChange">last change</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>\r
-                               <tr><th><wicket:message key="gb.url">URL</wicket:message></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>\r
+                               <tr><th><wicket:message key="gb.description">[description]</wicket:message></th><td><span wicket:id="repositoryDescription">[repository description]</span></td></tr>\r
+                               <tr><th><wicket:message key="gb.owner">[owner]</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>\r
+                               <tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>\r
+                               <tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="repositoryStats">[repository stats]</span></td></tr>\r
+                               <tr><th><wicket:message key="gb.url">[URL]</wicket:message></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>\r
                        </table>\r
                </div>\r
        </div>\r
index 6d28df6e51525a3b6f0ae7fa5bf6da87d0ff31ee..53a684b57bc57dee444e7f9006bf2343f568588b 100644 (file)
@@ -1,6 +1,8 @@
 package com.gitblit.wicket.pages;\r
 \r
+import java.awt.Color;\r
 import java.awt.Dimension;\r
+import java.text.MessageFormat;\r
 import java.util.List;\r
 \r
 import org.apache.wicket.PageParameters;\r
@@ -15,9 +17,13 @@ import com.codecommit.wicket.ChartAxisType;
 import com.codecommit.wicket.ChartProvider;\r
 import com.codecommit.wicket.ChartType;\r
 import com.codecommit.wicket.IChartData;\r
+import com.codecommit.wicket.LineStyle;\r
+import com.codecommit.wicket.MarkerType;\r
+import com.codecommit.wicket.ShapeMarker;\r
 import com.gitblit.GitBlit;\r
 import com.gitblit.Keys;\r
 import com.gitblit.utils.JGitUtils;\r
+import com.gitblit.utils.TimeUtils;\r
 import com.gitblit.wicket.RepositoryPage;\r
 import com.gitblit.wicket.WicketUtils;\r
 import com.gitblit.wicket.models.Metric;\r
@@ -44,11 +50,11 @@ public class SummaryPage extends RepositoryPage {
                }\r
 \r
                Repository r = getRepository();\r
-               List<Metric> metrics = JGitUtils.getDateMetrics(r);\r
-\r
-               long numberOfCommits = 0;\r
-               for (Metric m : metrics) {\r
-                       numberOfCommits += m.count;\r
+               List<Metric> metrics = null;\r
+               Metric metricsTotal = null;\r
+               if (GitBlit.self().settings().getBoolean(Keys.web.generateActivityGraph, true)) {\r
+                       metrics = JGitUtils.getDateMetrics(r);\r
+                       metricsTotal = metrics.remove(0);\r
                }\r
 \r
                // repository description\r
@@ -56,6 +62,11 @@ public class SummaryPage extends RepositoryPage {
                add(new Label("repositoryOwner", JGitUtils.getRepositoryOwner(r)));\r
 \r
                add(WicketUtils.createTimestampLabel("repositoryLastChange", JGitUtils.getLastChange(r), getTimeZone()));\r
+               if (metricsTotal == null) {\r
+                       add(new Label("repositoryStats", ""));\r
+               } else {\r
+                       add(new Label("repositoryStats", MessageFormat.format("{0} commits and {1} tags in {2}", metricsTotal.count, metricsTotal.tag, TimeUtils.duration(metricsTotal.duration))));\r
+               }\r
                add(new Label("repositoryCloneUrl", GitBlit.self().getCloneUrl(repositoryName)));\r
 \r
                add(new LogPanel("commitsPanel", repositoryName, null, r, numberCommits, 0));\r
@@ -75,7 +86,7 @@ public class SummaryPage extends RepositoryPage {
                if (GitBlit.self().settings().getBoolean(Keys.web.generateActivityGraph, true)) {\r
                        IChartData data = getChartData(metrics);\r
 \r
-                       ChartProvider provider = new ChartProvider(new Dimension(400, 80), ChartType.LINE, data);\r
+                       ChartProvider provider = new ChartProvider(new Dimension(400, 100), ChartType.LINE, data);\r
                        ChartAxis dateAxis = new ChartAxis(ChartAxisType.BOTTOM);\r
                        dateAxis.setLabels(new String[] { metrics.get(0).name, metrics.get(metrics.size() / 2).name, metrics.get(metrics.size() - 1).name });\r
                        provider.addAxis(dateAxis);\r
@@ -84,6 +95,9 @@ public class SummaryPage extends RepositoryPage {
                        commitAxis.setLabels(new String[] { "", String.valueOf((int) maxValue(metrics)) });\r
                        provider.addAxis(commitAxis);\r
 \r
+                       provider.setLineStyles(new LineStyle[] {new LineStyle(2, 4, 0), new LineStyle(0, 4, 1)});       \r
+                       provider.addShapeMarker(new ShapeMarker(MarkerType.DIAMOND, Color.BLUE, 1, -1, 5));\r
+                       \r
                        add(new Chart("commitsChart", provider));\r
                } else {\r
                        add(new ContextImage("commitsChart", "blank.png"));\r
@@ -91,23 +105,25 @@ public class SummaryPage extends RepositoryPage {
        }\r
 \r
        protected IChartData getChartData(List<Metric> metrics) {\r
-               final double[] counts = new double[metrics.size()];\r
+               final double[] commits = new double[metrics.size()];\r
+               final double[] tags = new double[metrics.size()];\r
                int i = 0;\r
                double max = 0;\r
                for (Metric m : metrics) {\r
-                       counts[i++] = m.count;\r
+                       commits[i] = m.count;\r
+                       if (m.tag > 0) {\r
+                               tags[i] = m.count;\r
+                       } else {\r
+                               tags[i] = -1d;\r
+                       }\r
                        max = Math.max(max, m.count);\r
+                       i++;\r
                }\r
-               final double dmax = max;\r
-               IChartData data = new AbstractChartData() {\r
+               IChartData data = new AbstractChartData(max) {\r
                        private static final long serialVersionUID = 1L;\r
 \r
                        public double[][] getData() {\r
-                               return new double[][] { counts };\r
-                       }\r
-\r
-                       public double getMax() {\r
-                               return dmax;\r
+                               return new double[][] { commits, tags };\r
                        }\r
                };\r
                return data;\r