]> source.dussan.org Git - gitblit.git/commitdiff
Implemented a graph servlet based on EGit/JGit's PlotWalk (issue-194)
authorJames Moger <james.moger@gitblit.com>
Wed, 14 Aug 2013 12:56:27 +0000 (08:56 -0400)
committerJames Moger <james.moger@gitblit.com>
Tue, 17 Sep 2013 21:34:00 +0000 (17:34 -0400)
The graph is generated server-side and therefore requires that the
commit table row height be fixed and match the row height of the
servlet.  There will be layout misalignment if remotes refs are
displayed.  Perhaps this can be improved in the future.

Change-Id: I39d0ffc7b1c3679976ce8c198c772ff86238f1a5

releases.moxie
src/main/distrib/data/gitblit.properties
src/main/java/WEB-INF/web.xml
src/main/java/com/gitblit/BranchGraphServlet.java [new file with mode: 0644]
src/main/java/com/gitblit/Constants.java
src/main/java/com/gitblit/wicket/panels/LogPanel.html
src/main/java/com/gitblit/wicket/panels/LogPanel.java
src/main/resources/gitblit.css
src/test/java/com/gitblit/tests/JGitUtilsTest.java

index 53ad8b5354fd398bfaabb17914e7e0aa879d5d7f..74cf1e33e97f4f0f7af1bf718bcc1f879f5e046d 100644 (file)
@@ -15,10 +15,12 @@ r20: {
        - Personal repository prefix (~) is now configurable (issue-265)
        - Updated default binary and Lucene ignore extensions
     additions:
+       - Added branch graph image servlet based on EGit's branch graph renderer (issue-194)
        - Added setting to control creating a repository as --shared on Unix servers (issue-263)
     dependencyChanges: ~
     settings:
     - { name: 'git.createRepositoriesShared', defaultValue: 'false' }
+       - { name: 'web.showBranchGraph', defaultValue: 'true' }
     contributors:
        - James Moger
        - Robin Rosenberg
index 1fe1561fedd7d133b5f61e38e7b966cecf15f0c5..3c0f1d1573e5d22386dcb4aba74613730f259f44 100644 (file)
@@ -900,6 +900,11 @@ web.showSearchTypeSelection = false
 # SINCE 0.5.0 \r
 web.generateActivityGraph = true\r
 \r
+# Displays the commits branch graph in the summary page and commits/log page.\r
+#\r
+# SINCE 1.4.0\r
+web.showBranchGraph = true\r
+\r
 # The default number of days to show on the activity page.\r
 # Value must exceed 0 else default of 7 is used\r
 #\r
index cf7146515a868262d2af6909e759d17b90ba848f..d4acb049ad4bcf4f697a22e68a91c1cae4723993 100644 (file)
                <url-pattern>/logo.png</url-pattern>\r
        </servlet-mapping>\r
 \r
+       <!-- Branch Graph Servlet\r
+                <url-pattern> MUST match: \r
+                       * Wicket Filter ignorePaths parameter -->\r
+       <servlet>\r
+               <servlet-name>BranchGraphServlet</servlet-name>\r
+               <servlet-class>com.gitblit.BranchGraphServlet</servlet-class>\r
+       </servlet>\r
+       <servlet-mapping>\r
+               <servlet-name>BranchGraphServlet</servlet-name>         \r
+               <url-pattern>/graph/*</url-pattern>\r
+       </servlet-mapping>\r
 \r
        <!-- Robots.txt Servlet\r
                 <url-pattern> MUST match: \r
                * PagesFilter <url-pattern>\r
                * PagesServlet <url-pattern>\r
                * com.gitblit.Constants.PAGES_PATH -->\r
-            <param-value>git/,feed/,zip/,federation/,rpc/,pages/,robots.txt,logo.png,sparkleshare/</param-value>\r
+            <param-value>git/,feed/,zip/,federation/,rpc/,pages/,robots.txt,logo.png,graph/,sparkleshare/</param-value>\r
         </init-param>\r
     </filter>\r
     <filter-mapping>\r
diff --git a/src/main/java/com/gitblit/BranchGraphServlet.java b/src/main/java/com/gitblit/BranchGraphServlet.java
new file mode 100644 (file)
index 0000000..8fca455
--- /dev/null
@@ -0,0 +1,363 @@
+/*\r
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>\r
+ * Copyright 2013 gitblit.com.\r
+ * and other copyright owners as documented in the project's IP log.\r
+ *\r
+ * This program and the accompanying materials are made available\r
+ * under the terms of the Eclipse Distribution License v1.0 which\r
+ * accompanies this distribution, is reproduced below, and is\r
+ * available at http://www.eclipse.org/org/documents/edl-v10.php\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit;\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.Graphics;\r
+import java.awt.Graphics2D;\r
+import java.awt.RenderingHints;\r
+import java.awt.Stroke;\r
+import java.awt.image.BufferedImage;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+\r
+import javax.imageio.ImageIO;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.http.HttpServlet;\r
+import javax.servlet.http.HttpServletRequest;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import org.eclipse.jgit.lib.Ref;\r
+import org.eclipse.jgit.lib.Repository;\r
+import org.eclipse.jgit.revplot.AbstractPlotRenderer;\r
+import org.eclipse.jgit.revplot.PlotCommit;\r
+import org.eclipse.jgit.revplot.PlotCommitList;\r
+import org.eclipse.jgit.revplot.PlotLane;\r
+import org.eclipse.jgit.revplot.PlotWalk;\r
+import org.eclipse.jgit.revwalk.RevCommit;\r
+\r
+import com.gitblit.utils.JGitUtils;\r
+import com.gitblit.utils.StringUtils;\r
+\r
+/**\r
+ * Handles requests for branch graphs\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
+public class BranchGraphServlet extends HttpServlet {\r
+\r
+       private static final long serialVersionUID = 1L;\r
+\r
+       private static final int LANE_WIDTH = 14;\r
+\r
+       // must match tr.commit css height\r
+       private static final int ROW_HEIGHT = 24;\r
+\r
+       private static final int RIGHT_PAD = 2;\r
+\r
+       private final Stroke[] strokeCache;\r
+\r
+       public BranchGraphServlet() {\r
+               super();\r
+\r
+               strokeCache = new Stroke[4];\r
+               for (int i = 1; i < strokeCache.length; i++)\r
+                       strokeCache[i] = new BasicStroke(i);\r
+       }\r
+\r
+       /**\r
+        * Returns an url to this servlet for the specified parameters.\r
+        * \r
+        * @param baseURL\r
+        * @param repository\r
+        * @param objectId\r
+        * @param numberCommits\r
+        * @return an url\r
+        */\r
+       public static String asLink(String baseURL, String repository, String objectId, int numberCommits) {\r
+               if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {\r
+                       baseURL = baseURL.substring(0, baseURL.length() - 1);\r
+               }\r
+               return baseURL + Constants.BRANCH_GRAPH_PATH + "?r=" + repository\r
+                               + (objectId == null ? "" : ("&h=" + objectId))\r
+                               + (numberCommits > 0 ? ("&l=" + numberCommits) : "");\r
+       }\r
+\r
+       @Override\r
+       protected long getLastModified(HttpServletRequest req) {\r
+               String repository = req.getParameter("r");\r
+               String objectId = req.getParameter("h");\r
+               Repository r = null;\r
+               try {\r
+                       r = GitBlit.self().getRepository(repository);\r
+                       if (StringUtils.isEmpty(objectId)) {\r
+                               objectId = JGitUtils.getHEADRef(r);\r
+                       }\r
+                       RevCommit commit = JGitUtils.getCommit(r, objectId);\r
+                       return JGitUtils.getCommitDate(commit).getTime();\r
+               } finally {\r
+                       if (r != null) {\r
+                               r.close();\r
+                       }\r
+               }\r
+       }\r
+\r
+       @Override\r
+       protected void doGet(HttpServletRequest request, HttpServletResponse response)\r
+                       throws ServletException, IOException {\r
+               InputStream is = null;\r
+               Repository r = null;\r
+               PlotWalk rw = null;\r
+               try {\r
+                       String repository = request.getParameter("r");\r
+                       String objectId = request.getParameter("h");\r
+                       String length = request.getParameter("l");\r
+\r
+                       r = GitBlit.self().getRepository(repository);\r
+\r
+                       rw = new PlotWalk(r);\r
+                       if (StringUtils.isEmpty(objectId)) {\r
+                               objectId = JGitUtils.getHEADRef(r);\r
+                       }\r
+\r
+                       rw.markStart(rw.lookupCommit(r.resolve(objectId)));\r
+\r
+                       // default to the items-per-page setting, unless specified\r
+                       int maxCommits = GitBlit.getInteger(Keys.web.itemsPerPage, 50);\r
+                       if (!StringUtils.isEmpty(length)) {\r
+                               int l = Integer.parseInt(length);\r
+                               if (l > 0) {\r
+                                       maxCommits = l;\r
+                               }\r
+                       }\r
+\r
+                       // fetch the requested commits plus some extra so that the last\r
+                       // commit displayed *likely* has correct lane assignments  \r
+                       CommitList commitList = new CommitList();\r
+                       commitList.source(rw);\r
+                       commitList.fillTo(2*maxCommits);\r
+\r
+                       // determine the appropriate width for the image\r
+                       int numLanes = 0;\r
+                       int numCommits = Math.min(maxCommits, commitList.size());                       \r
+                       for (int i = 0; i < numCommits; i++) {\r
+                               PlotCommit<Lane> commit = commitList.get(i);\r
+                               int pos = commit.getLane().getPosition();\r
+                               numLanes = Math.max(numLanes, pos + 1);\r
+                       }\r
+\r
+                       int graphWidth = numLanes * LANE_WIDTH + RIGHT_PAD;\r
+                       int rowHeight = ROW_HEIGHT;\r
+\r
+                       // create an image buffer and render the lanes\r
+                       BufferedImage image = new BufferedImage(graphWidth, rowHeight*numCommits, BufferedImage.TYPE_INT_ARGB);\r
+                       Graphics2D g = null;\r
+                       try {\r
+                               g = image.createGraphics();\r
+                               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\r
+                               LanesRenderer renderer = new LanesRenderer();\r
+                               for (int i = 0; i < numCommits; i++) {\r
+                                       PlotCommit<Lane> commit = commitList.get(i);\r
+                                       Graphics row = g.create(0, i*rowHeight, graphWidth, rowHeight);\r
+                                       try {\r
+                                               renderer.paint(row, commit, rowHeight, graphWidth);\r
+                                       } finally {\r
+                                               row.dispose();\r
+                                               row = null;\r
+                                       }\r
+                               }\r
+                       } finally {\r
+                               if (g != null) {\r
+                                       g.dispose();\r
+                                       g = null;\r
+                               }\r
+                       }\r
+\r
+                       // write the image buffer to the client\r
+                       response.setContentType("image/png");\r
+                       if (numCommits > 0) {\r
+                               response.setHeader("Cache-Control", "public, max-age=60, must-revalidate");\r
+                               response.setDateHeader("Last-Modified", JGitUtils.getCommitDate(commitList.get(0)).getTime());\r
+                       }\r
+                       OutputStream os = response.getOutputStream();\r
+                       ImageIO.write(image, "png", os);\r
+                       os.flush();\r
+                       image.flush();\r
+                       image = null;\r
+               } catch (Exception e) {\r
+                       e.printStackTrace();\r
+               } finally {\r
+                       if (is != null) {\r
+                               is.close();\r
+                               is = null;\r
+                       }\r
+                       if (rw != null) {\r
+                               rw.dispose();\r
+                               rw = null;\r
+                       }\r
+                       if (r != null) {\r
+                               r.close();\r
+                               r = null;\r
+                       }\r
+               }\r
+       }\r
+\r
+       private Stroke stroke(final int width) {\r
+               if (width < strokeCache.length)\r
+                       return strokeCache[width];\r
+               return new BasicStroke(width);\r
+       }\r
+\r
+       static class CommitList extends PlotCommitList<Lane> {\r
+               final List<Color> laneColors;\r
+               final LinkedList<Color> colors;\r
+\r
+               CommitList() {\r
+                       laneColors = new ArrayList<Color>();\r
+                       laneColors.add(new Color(133, 166, 214));\r
+                       laneColors.add(new Color(221, 205, 93));\r
+                       laneColors.add(new Color(199, 134, 57));\r
+                       laneColors.add(new Color(131, 150, 98));\r
+                       laneColors.add(new Color(197, 123, 127));\r
+                       laneColors.add(new Color(139, 136, 140));\r
+                       laneColors.add(new Color(48, 135, 144));\r
+                       laneColors.add(new Color(190, 93, 66));\r
+                       laneColors.add(new Color(143, 163, 54));\r
+                       laneColors.add(new Color(180, 148, 74));\r
+                       laneColors.add(new Color(101, 101, 217));\r
+                       laneColors.add(new Color(72, 153, 119));\r
+                       laneColors.add(new Color(23, 101, 160));\r
+                       laneColors.add(new Color(132, 164, 118));\r
+                       laneColors.add(new Color(255, 230, 59));\r
+                       laneColors.add(new Color(136, 176, 70));\r
+                       laneColors.add(new Color(255, 138, 1));\r
+                       laneColors.add(new Color(123, 187, 95));\r
+                       laneColors.add(new Color(233, 88, 98));\r
+                       laneColors.add(new Color(93, 158, 254));\r
+                       laneColors.add(new Color(175, 215, 0));\r
+                       laneColors.add(new Color(140, 134, 142));\r
+                       laneColors.add(new Color(232, 168, 21));\r
+                       laneColors.add(new Color(0, 172, 191));\r
+                       laneColors.add(new Color(251, 58, 4));\r
+                       laneColors.add(new Color(63, 64, 255));\r
+                       laneColors.add(new Color(27, 194, 130));\r
+                       laneColors.add(new Color(0, 104, 183));\r
+\r
+                       colors = new LinkedList<Color>();\r
+                       repackColors();\r
+               }\r
+\r
+               private void repackColors() {\r
+                       colors.addAll(laneColors);\r
+               }\r
+\r
+               @Override\r
+               protected Lane createLane() {\r
+                       final Lane lane = new Lane();\r
+                       if (colors.isEmpty())\r
+                               repackColors();\r
+                       lane.color = colors.removeFirst();\r
+                       return lane;\r
+               }\r
+\r
+               @Override\r
+               protected void recycleLane(final Lane lane) {\r
+                       colors.add(lane.color);\r
+               }\r
+       }\r
+\r
+       static class Lane extends PlotLane {\r
+\r
+               private static final long serialVersionUID = 1L;\r
+\r
+               Color color;\r
+\r
+               @Override\r
+               public boolean equals(Object o) {\r
+                       return super.equals(o) && color.equals(((Lane)o).color);\r
+               }\r
+\r
+               @Override\r
+               public int hashCode() {\r
+                       return super.hashCode() ^ color.hashCode();\r
+               }\r
+       }\r
+\r
+       class LanesRenderer extends AbstractPlotRenderer<Lane, Color> implements Serializable {\r
+\r
+               private static final long serialVersionUID = 1L;\r
+\r
+               final Color commitDotFill = new Color(220, 220, 220);\r
+\r
+               final Color commitDotOutline = new Color(110, 110, 110);\r
+\r
+               transient Graphics2D g;\r
+\r
+               void paint(Graphics in, PlotCommit<Lane> commit, int h, int w) {\r
+                       g = (Graphics2D) in.create();\r
+                       try {\r
+                               if (commit != null)\r
+                                       paintCommit(commit, h);\r
+                       } finally {\r
+                               g.dispose();\r
+                               g = null;\r
+                       }\r
+               }\r
+\r
+               @Override\r
+               protected void drawLine(Color color, int x1, int y1, int x2, int y2, int width) {\r
+                       if (y1 == y2) {\r
+                               x1 -= width / 2;\r
+                               x2 -= width / 2;\r
+                       } else if (x1 == x2) {\r
+                               y1 -= width / 2;\r
+                               y2 -= width / 2;\r
+                       }\r
+\r
+                       g.setColor(color);\r
+                       g.setStroke(stroke(width));\r
+                       g.drawLine(x1, y1, x2, y2);\r
+               }\r
+\r
+               @Override\r
+               protected void drawCommitDot(int x, int y, int w, int h) {\r
+                       g.setColor(commitDotFill);\r
+                       g.setStroke(strokeCache[2]);\r
+                       g.fillOval(x + 2, y + 1, w - 2, h - 2);\r
+                       g.setColor(commitDotOutline);\r
+                       g.drawOval(x + 2, y + 1, w - 2, h - 2);\r
+               }\r
+\r
+               @Override\r
+               protected void drawBoundaryDot(int x, int y, int w, int h) {\r
+                       drawCommitDot(x, y, w, h);\r
+               }\r
+\r
+               @Override\r
+               protected void drawText(String msg, int x, int y) {\r
+               }\r
+\r
+               @Override\r
+               protected Color laneColor(Lane myLane) {\r
+                       return myLane != null ? myLane.color : Color.black;\r
+               }\r
+\r
+               @Override\r
+               protected int drawLabel(int x, int y, Ref ref) {\r
+                       return 0;\r
+               }\r
+       }\r
+}\r
index a3a3c70efd91c507ba279e8b2774470b15d1df55..88a1022383cca88aeaa9533ad9622be427748b46 100644 (file)
@@ -63,6 +63,8 @@ public class Constants {
        public static final String PAGES = "/pages/";\r
        \r
        public static final String SPARKLESHARE_INVITE_PATH = "/sparkleshare/";\r
+       \r
+       public static final String BRANCH_GRAPH_PATH = "/graph/";\r
 \r
        public static final String BORDER = "***********************************************************";\r
 \r
index 1abda874fd18bf31679b23ae44940c1b63568dde..fde9a3e7e4a06ffbaf6075caa18c7cbd21bebacc 100644 (file)
        <div class="header"><i class="icon-refresh"></i> <b><span wicket:id="header">[log header]</span></b></div>\r
        <table class="pretty">\r
                <tbody>\r
-                       <tr wicket:id="commit">\r
+                       <tr class="hidden-phone hidden-tablet">\r
+                               <td wicket:id="graph" class="graph"><img wicket:id="image"></img></td>\r
+                               <td></td>\r
+                               <td></td>\r
+                               <td></td>\r
+                               <td></td>\r
+                               <td></td>\r
+                               <td></td>\r
+                       </tr>\r
+                       <tr class="commit" wicket:id="commit">\r
                        <td class="date" style="width:6em;"><span wicket:id="commitDate">[commit date]</span></td>\r
-                       <td class="hidden-phone author"><span wicket:id="commitAuthor">[commit author]</span></td>\r
+                       <td class="hidden-phone author ellipsize"><span wicket:id="commitAuthor">[commit author]</span></td>\r
                        <td class="hidden-phone icon"><img wicket:id="commitIcon" /></td>\r
-                       <td class="message"><table class="nestedTable"><tr><td><span style="vertical-align:middle;" wicket:id="commitShortMessage">[commit short message]</span></td><td><div style="text-align:right;" wicket:id="commitRefs">[commit refs]</div></td></tr></table></td>\r
+                       <td class="message ellipsize">\r
+                               <table class="nestedTable">\r
+                                       <tr>\r
+                                               <td class="ellipsize"><span style="vertical-align:middle;" wicket:id="commitShortMessage">[commit short message]</span></td>\r
+                                               <td><div style="text-align:right;" wicket:id="commitRefs">[commit refs]</div></td>\r
+                                       </tr>\r
+                               </table>\r
+                       </td>\r
                        <td class="hidden-phone hidden-tablet rightAlign"><span wicket:id="hashLink">[hash link]</span></td>\r
-                       <td class="hidden-phone hidden-tablet rightAlign">\r
+                       <td class="hidden-phone hidden-tablet rightAlign" style="white-space: nowrap;">\r
                                <span class="link">\r
                                                <a wicket:id="diff"><wicket:message key="gb.diff"></wicket:message></a> | <a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a>\r
                                        </span>\r
index 6c523be68e8c6f30ac17a76befd3945ece9cc553..a8f3d556137ef1883a8ea0a1ea44fcbeef9f6321 100644 (file)
@@ -19,6 +19,9 @@ import java.util.Date;
 import java.util.List;\r
 import java.util.Map;\r
 \r
+import org.apache.wicket.MarkupContainer;\r
+import org.apache.wicket.behavior.SimpleAttributeModifier;\r
+import org.apache.wicket.markup.html.WebMarkupContainer;\r
 import org.apache.wicket.markup.html.basic.Label;\r
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
 import org.apache.wicket.markup.repeater.Item;\r
@@ -32,9 +35,11 @@ import org.eclipse.jgit.revwalk.RevCommit;
 import com.gitblit.Constants;\r
 import com.gitblit.GitBlit;\r
 import com.gitblit.Keys;\r
+import com.gitblit.BranchGraphServlet;\r
 import com.gitblit.models.RefModel;\r
 import com.gitblit.utils.JGitUtils;\r
 import com.gitblit.utils.StringUtils;\r
+import com.gitblit.wicket.ExternalImage;\r
 import com.gitblit.wicket.WicketUtils;\r
 import com.gitblit.wicket.pages.CommitDiffPage;\r
 import com.gitblit.wicket.pages.CommitPage;\r
@@ -70,6 +75,20 @@ public class LogPanel extends BasePanel {
                // inaccurate way to determine if there are more commits.\r
                // works unless commits.size() represents the exact end.\r
                hasMore = commits.size() >= itemsPerPage;\r
+               \r
+               final String baseUrl = WicketUtils.getGitblitURL(getRequest());\r
+               final boolean showGraph = GitBlit.getBoolean(Keys.web.showBranchGraph, true);\r
+               \r
+               MarkupContainer graph = new WebMarkupContainer("graph");\r
+               add(graph);\r
+               if (!showGraph || commits.isEmpty()) {\r
+                       // not showing or nothing to show\r
+                       graph.setVisible(false);\r
+               } else {\r
+                       // set the rowspan on the graph row and +1 for the graph row itself\r
+                       graph.add(new SimpleAttributeModifier("rowspan", "" + (commits.size() + 1)));\r
+                       graph.add(new ExternalImage("image", BranchGraphServlet.asLink(baseUrl, repositoryName, commits.get(0).name(), commits.size())));\r
+               }\r
 \r
                // header\r
                if (pageResults) {\r
index 4db15486192865b8049ef7a88cd242c2a9f48272..d8745bf4d2ad03aed28888316d9d30b772fcff70 100644 (file)
@@ -1146,6 +1146,32 @@ table.pretty table.nestedTable {
        margin-bottom: 0px !important;\r
 }\r
 \r
+table.pretty td.graph {\r
+       border-right: 1px solid #ddd;\r
+       border-bottom: 1px solid #ddd;\r
+}\r
+\r
+table.pretty tr.commit {\r
+       /* must match branch graph servlet row height definition */\r
+       height: 24px;\r
+}\r
+\r
+@media (min-width: 768px) {\r
+  td.ellipsize {\r
+       text-overflow: ellipsis;\r
+       overflow: hidden;\r
+       white-space: nowrap;\r
+  }\r
+}\r
+\r
+@media (max-width: 767px) {\r
+  td.ellipsize {\r
+    text-overflow: inherit;\r
+    overflow: visible;\r
+    white-space: wrap;\r
+  }    \r
+}\r
+\r
 table.comments td {\r
        padding: 4px;\r
        line-height: 17px;\r
@@ -1204,7 +1230,7 @@ table.palette td.header {
        font-weight: bold; \r
        background-color: #ffffff !important;\r
        padding-top: 0px !important;\r
-       margin-bottom: 0 !imporant;     \r
+       margin-bottom: 0 !important;    \r
        border: 0 !important;\r
        border-radius: 0 !important;\r
        line-height: 1em;\r
index 463c0a848578323fd6e95a98f4b9909264b33515..06fd674af333425b9d23fbcd8e0b9b1f84c3f5d1 100644 (file)
@@ -37,6 +37,10 @@ import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Repository;\r
 import org.eclipse.jgit.lib.RepositoryCache;\r
 import org.eclipse.jgit.lib.RepositoryCache.FileKey;\r
+import org.eclipse.jgit.revplot.PlotCommit;\r
+import org.eclipse.jgit.revplot.PlotCommitList;\r
+import org.eclipse.jgit.revplot.PlotLane;\r
+import org.eclipse.jgit.revplot.PlotWalk;\r
 import org.eclipse.jgit.revwalk.RevCommit;\r
 import org.eclipse.jgit.revwalk.RevTree;\r
 import org.eclipse.jgit.util.FS;\r
@@ -602,5 +606,17 @@ public class JGitUtilsTest {
                assertTrue(zipFileB.length() > 0);\r
                zipFileB.delete();\r
        }\r
-\r
+       \r
+       @Test\r
+       public void testPlots() throws Exception {\r
+               Repository repository = GitBlitSuite.getTicgitRepository();\r
+               PlotWalk pw = new PlotWalk(repository);\r
+               PlotCommitList<PlotLane> commits = new PlotCommitList<PlotLane>();\r
+               commits.source(pw);\r
+               commits.fillTo(25);\r
+               for (PlotCommit<PlotLane> commit : commits) {\r
+                       System.out.println(commit);\r
+               }\r
+               repository.close();\r
+       }\r
 }
\ No newline at end of file