From cd9461c0c05958444d1313b794be57df39d98956 Mon Sep 17 00:00:00 2001 From: Bret K. Ikehara <bret.k.ikehara@gmail.com> Date: Wed, 18 Sep 2013 11:29:45 -0400 Subject: [PATCH] Add support for rendering Markdown commit messages (issue-203) --- src/main/java/com/gitblit/SyndicationServlet.java | 2 src/main/java/com/gitblit/wicket/pages/RepositoryPage.java | 17 +++-- src/main/java/com/gitblit/Constants.java | 13 ++++ src/main/java/com/gitblit/wicket/pages/TagPage.html | 2 src/main/distrib/data/gitblit.properties | 8 ++ src/main/java/com/gitblit/GitBlit.java | 69 +++++++++++++++++++++- src/main/java/com/gitblit/wicket/GitBlitWebApp.properties | 3 src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java | 2 src/main/java/com/gitblit/wicket/pages/CommitPage.html | 2 src/main/java/com/gitblit/wicket/pages/TagPage.java | 2 src/main/java/com/gitblit/models/RepositoryModel.java | 2 src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html | 2 src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html | 15 ++-- src/main/resources/gitblit.css | 3 + src/main/java/com/gitblit/wicket/pages/CommitPage.java | 6 +- src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java | 6 + 16 files changed, 125 insertions(+), 29 deletions(-) diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index 3c0f1d1..311152a 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -878,6 +878,14 @@ # SINCE 0.8.0 web.repositoryListSwatches = true +# Defines the default commit message renderer. This can be configured +# per-repository. +# +# Valid values are: plain, markdown +# +# SINCE 1.4.0 +web.commitMessageRenderer = plain + # Choose the diff presentation style: gitblt, gitweb, or plain # # SINCE 0.5.0 diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java index 88a1022..bd04128 100644 --- a/src/main/java/com/gitblit/Constants.java +++ b/src/main/java/com/gitblit/Constants.java @@ -490,6 +490,19 @@ return this == LOCAL; } } + + public static enum CommitMessageRenderer { + PLAIN, MARKDOWN; + + public static CommitMessageRenderer fromName(String name) { + for (CommitMessageRenderer renderer : values()) { + if (renderer.name().equalsIgnoreCase(name)) { + return renderer; + } + } + return CommitMessageRenderer.PLAIN; + } + } @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java index 8c0d62d..95da669 100644 --- a/src/main/java/com/gitblit/GitBlit.java +++ b/src/main/java/com/gitblit/GitBlit.java @@ -32,6 +32,7 @@ import java.nio.charset.Charset; import java.security.Principal; import java.text.MessageFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -87,6 +88,7 @@ import com.gitblit.Constants.AccountType; import com.gitblit.Constants.AuthenticationType; import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.CommitMessageRenderer; import com.gitblit.Constants.FederationRequest; import com.gitblit.Constants.FederationStrategy; import com.gitblit.Constants.FederationToken; @@ -124,6 +126,7 @@ import com.gitblit.utils.JGitUtils; import com.gitblit.utils.JGitUtils.LastChange; import com.gitblit.utils.JsonUtils; +import com.gitblit.utils.MarkdownUtils; import com.gitblit.utils.MetricUtils; import com.gitblit.utils.ModelUtils; import com.gitblit.utils.ObjectCache; @@ -2014,6 +2017,8 @@ model.showReadme = getConfig(config, "showReadme", false); model.skipSizeCalculation = getConfig(config, "skipSizeCalculation", false); model.skipSummaryMetrics = getConfig(config, "skipSummaryMetrics", false); + model.commitMessageRenderer = CommitMessageRenderer.fromName(getConfig(config, "commitMessageRenderer", + settings.getString(Keys.web.commitMessageRenderer, null))); model.federationStrategy = FederationStrategy.fromName(getConfig(config, "federationStrategy", null)); model.federationSets = new ArrayList<String>(Arrays.asList(config.getStringList( @@ -2041,7 +2046,7 @@ 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>(); for (String aProperty : config.getNames(Constants.CONFIG_GITBLIT, Constants.CONFIG_CUSTOM_FIELDS)) { @@ -2596,6 +2601,16 @@ config.setInt(Constants.CONFIG_GITBLIT, null, "maxActivityCommits", repository.maxActivityCommits); } + CommitMessageRenderer defaultRenderer = CommitMessageRenderer.fromName(settings.getString(Keys.web.commitMessageRenderer, null)); + if (repository.commitMessageRenderer == null || repository.commitMessageRenderer == defaultRenderer) { + // use default from config + config.unset(Constants.CONFIG_GITBLIT, null, "commitMessageRenderer"); + } else { + // repository overrides default + config.setString(Constants.CONFIG_GITBLIT, null, "commitMessageRenderer", + repository.commitMessageRenderer.name()); + } + updateList(config, "federationSets", repository.federationSets); updateList(config, "preReceiveScript", repository.preReceiveScripts); updateList(config, "postReceiveScript", repository.postReceiveScripts); @@ -2685,12 +2700,56 @@ * Returns an html version of the commit message with any global or * repository-specific regular expression substitution applied. * + * This method uses the preferred renderer to transform the commit message. + * + * @param repository + * @param text + * @return html version of the commit message + */ + public String processCommitMessage(RepositoryModel repository, String text) { + switch (repository.commitMessageRenderer) { + case MARKDOWN: + try { + String prepared = processCommitMessageRegex(repository.name, text); + return MarkdownUtils.transformMarkdown(prepared); + } catch (ParseException e) { + logger.error("Failed to render commit message as markdown", e); + } + break; + default: + // noop + break; + } + + return processPlainCommitMessage(repository.name, text); + } + + /** + * Returns an html version of the commit message with any global or + * repository-specific regular expression substitution applied. + * + * This method assumes the commit message is plain text. + * * @param repositoryName * @param text * @return html version of the commit message */ - public String processCommitMessage(String repositoryName, String text) { - String html = StringUtils.breakLinesForHtml(text); + public String processPlainCommitMessage(String repositoryName, String text) { + String html = StringUtils.escapeForHtml(text, false); + html = processCommitMessageRegex(repositoryName, html); + return StringUtils.breakLinesForHtml(html); + + } + + /** + * Apply globally or per-repository specified regex substitutions to the + * commit message. + * + * @param repositoryName + * @param text + * @return the processed commit message + */ + protected String processCommitMessageRegex(String repositoryName, String text) { Map<String, String> map = new HashMap<String, String>(); // global regex keys if (settings.getBoolean(Keys.regex.global, false)) { @@ -2714,14 +2773,14 @@ String definition = entry.getValue().trim(); String[] chunks = definition.split("!!!"); if (chunks.length == 2) { - html = html.replaceAll(chunks[0], chunks[1]); + text = text.replaceAll(chunks[0], chunks[1]); } else { logger.warn(entry.getKey() + " improperly formatted. Use !!! to separate match from replacement: " + definition); } } - return html; + return text; } /** diff --git a/src/main/java/com/gitblit/SyndicationServlet.java b/src/main/java/com/gitblit/SyndicationServlet.java index baaf7eb..bdb3b57 100644 --- a/src/main/java/com/gitblit/SyndicationServlet.java +++ b/src/main/java/com/gitblit/SyndicationServlet.java @@ -244,7 +244,7 @@ StringUtils.encodeURL(model.name.replace('/', fsc)), commit.getName()); entry.published = commit.getCommitterIdent().getWhen(); entry.contentType = "text/html"; - String message = GitBlit.self().processCommitMessage(model.name, + String message = GitBlit.self().processCommitMessage(model, commit.getFullMessage()); entry.content = message; entry.repository = model.name; diff --git a/src/main/java/com/gitblit/models/RepositoryModel.java b/src/main/java/com/gitblit/models/RepositoryModel.java index e28c9df..f0354b9 100644 --- a/src/main/java/com/gitblit/models/RepositoryModel.java +++ b/src/main/java/com/gitblit/models/RepositoryModel.java @@ -26,6 +26,7 @@ import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.CommitMessageRenderer; import com.gitblit.Constants.FederationStrategy; import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.ModelUtils; @@ -85,6 +86,7 @@ public int gcPeriod; public int maxActivityCommits; public List<String> metricAuthorExclusions; + public CommitMessageRenderer commitMessageRenderer; public transient boolean isCollectingGarbage; public Date lastGC; diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 55d8987..1f1a584 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -501,4 +501,5 @@ gb.todaysActivityStats = today / {1} commits by {2} authors gb.todaysActivityNone = today / none gb.noActivityToday = there has been no activity today -gb.anonymousUser= anonymous \ No newline at end of file +gb.anonymousUser= anonymous +gb.commitMessageRenderer = commit message renderer \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html index 11a0ce3..7437d2e 100644 --- a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html +++ b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html @@ -16,7 +16,7 @@ <div wicket:id="commitHeader">[commit header]</div> <!-- full message --> - <pre style="border-style:none" "class="commit_message" wicket:id="fullMessage">[commit message]</pre> + <div wicket:id="fullMessage">[commit message]</div> <!-- commit legend --> <div class="hidden-phone" style="text-align:right;" wicket:id="commitLegend"></div> diff --git a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java index 6f1b459..0a41b67 100644 --- a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java +++ b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java @@ -79,7 +79,7 @@ add(new CommitHeaderPanel("commitHeader", repositoryName, commit)); - addFullText("fullMessage", commit.getFullMessage(), true); + addFullText("fullMessage", commit.getFullMessage()); // changed paths list List<PathChangeModel> paths = JGitUtils.getFilesInCommit(r, commit); diff --git a/src/main/java/com/gitblit/wicket/pages/CommitPage.html b/src/main/java/com/gitblit/wicket/pages/CommitPage.html index ab5ddca..1ec541c 100644 --- a/src/main/java/com/gitblit/wicket/pages/CommitPage.html +++ b/src/main/java/com/gitblit/wicket/pages/CommitPage.html @@ -49,7 +49,7 @@ </div> <!-- full message --> - <pre class="commit_message" wicket:id="fullMessage">[commit message]</pre> + <div class="topborder" wicket:id="fullMessage">[commit message]</div> <!-- git notes --> <table class="gitnotes"> diff --git a/src/main/java/com/gitblit/wicket/pages/CommitPage.java b/src/main/java/com/gitblit/wicket/pages/CommitPage.java index 1d11d44..1a1d598 100644 --- a/src/main/java/com/gitblit/wicket/pages/CommitPage.java +++ b/src/main/java/com/gitblit/wicket/pages/CommitPage.java @@ -117,7 +117,7 @@ }; add(parentsView); - addFullText("fullMessage", c.getFullMessage(), true); + addFullText("fullMessage", c.getFullMessage()); // git notes List<GitNote> notes = JGitUtils.getNotesOnCommit(r, c); @@ -133,8 +133,8 @@ item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent())); item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef .getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils())); - item.add(new Label("noteContent", GitBlit.self().processCommitMessage( - repositoryName, entry.content)).setEscapeModelStrings(false)); + item.add(new Label("noteContent", GitBlit.self().processPlainCommitMessage(repositoryName, + entry.content)).setEscapeModelStrings(false)); } }; add(notesView.setVisible(notes.size() > 0)); diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html index 3807027..f7d1f73 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -42,8 +42,9 @@ <tr><th><wicket:message key="gb.skipSummaryMetrics"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSummaryMetrics" tabindex="12" /> <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" /> <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><wicket:message key="gb.commitMessageRenderer"></wicket:message></th><td class="edit"><select class="span2" wicket:id="commitMessageRenderer" tabindex="15" /></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="15" /></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="16" /></td></tr> </tbody> </table> </div> @@ -52,15 +53,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="16" /> </td></tr> + <tr><th><wicket:message key="gb.owners"></wicket:message></th><td class="edit"><span wicket:id="owners" tabindex="17" /> </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="17" /></td></tr> + <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="18" /></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="18" /> <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" /> <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" /> <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="19" /> <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="20" /> <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="21" /> <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> @@ -73,7 +74,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="21" /></td></tr> + <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="22" /></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> diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index 4c471a1..a25797f 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -52,6 +52,7 @@ import com.gitblit.Constants; import com.gitblit.Constants.AccessRestrictionType; import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.CommitMessageRenderer; import com.gitblit.Constants.FederationStrategy; import com.gitblit.Constants.RegistrantType; import com.gitblit.GitBlit; @@ -552,6 +553,10 @@ } }); + List<CommitMessageRenderer> renderers = Arrays.asList(CommitMessageRenderer.values()); + DropDownChoice<CommitMessageRenderer> messageRendererChoice = new DropDownChoice<CommitMessageRenderer>("commitMessageRenderer", renderers); + form.add(messageRendererChoice); + form.add(new Button("save")); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; @@ -721,5 +726,4 @@ return Integer.toString(index); } } - } diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java index afbed86..e5ce22a 100644 --- a/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RepositoryPage.java @@ -482,12 +482,17 @@ add(new RefsPanel("refsPanel", repositoryName, c, JGitUtils.getAllRefs(r, getRepositoryModel().showRemoteBranches))); } - protected void addFullText(String wicketId, String text, boolean substituteRegex) { - String html = StringUtils.escapeForHtml(text, false); - if (substituteRegex) { - html = GitBlit.self().processCommitMessage(repositoryName, html); - } else { - html = StringUtils.breakLinesForHtml(html); + protected void addFullText(String wicketId, String text) { + RepositoryModel model = getRepositoryModel(); + String content = GitBlit.self().processCommitMessage(model, text); + String html; + switch (model.commitMessageRenderer) { + case MARKDOWN: + html = MessageFormat.format("<div class='commit_message'>{0}</div>", content); + break; + default: + html = MessageFormat.format("<pre class='commit_message'>{0}</pre>", content); + break; } add(new Label(wicketId, html).setEscapeModelStrings(false)); } diff --git a/src/main/java/com/gitblit/wicket/pages/TagPage.html b/src/main/java/com/gitblit/wicket/pages/TagPage.html index e719a39..492ece3 100644 --- a/src/main/java/com/gitblit/wicket/pages/TagPage.html +++ b/src/main/java/com/gitblit/wicket/pages/TagPage.html @@ -22,7 +22,7 @@ </div> <!-- full message --> - <pre class="commit_message" wicket:id="fullMessage">[commit message]</pre> + <div class="topborder" wicket:id="fullMessage">[commit message]</div> <wicket:fragment wicket:id="fullPersonIdent"> <span wicket:id="personName"></span><span wicket:id="personAddress"></span> diff --git a/src/main/java/com/gitblit/wicket/pages/TagPage.java b/src/main/java/com/gitblit/wicket/pages/TagPage.java index 13c1011..b8b6eef 100644 --- a/src/main/java/com/gitblit/wicket/pages/TagPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TagPage.java @@ -92,7 +92,7 @@ } add(WicketUtils.createTimestampLabel("tagDate", when, getTimeZone(), getTimeUtils())); - addFullText("fullMessage", tagRef.getFullMessage(), true); + addFullText("fullMessage", tagRef.getFullMessage()); } @Override diff --git a/src/main/resources/gitblit.css b/src/main/resources/gitblit.css index d8745bf..eef0d0b 100644 --- a/src/main/resources/gitblit.css +++ b/src/main/resources/gitblit.css @@ -891,6 +891,9 @@ .commit_message { padding: 8px; +} + +.topborder { border: solid #ddd; border-width: 1px 0px 0px; border-radius: 0px; -- Gitblit v1.9.1