@@ -878,6 +878,14 @@ web.repositoryRootGroupName = main | |||
# 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 |
@@ -490,6 +490,19 @@ public class Constants { | |||
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) |
@@ -32,6 +32,7 @@ import java.net.URISyntaxException; | |||
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.AccessRestrictionType; | |||
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.HttpUtils; | |||
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 @@ public class GitBlit implements ServletContextListener { | |||
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 @@ public class GitBlit implements ServletContextListener { | |||
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 @@ public class GitBlit implements ServletContextListener { | |||
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 @@ public class GitBlit implements ServletContextListener { | |||
* 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 @@ public class GitBlit implements ServletContextListener { | |||
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; | |||
} | |||
/** |
@@ -244,7 +244,7 @@ public class SyndicationServlet extends HttpServlet { | |||
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; |
@@ -26,6 +26,7 @@ import java.util.TreeSet; | |||
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 class RepositoryModel implements Serializable, Comparable<RepositoryModel | |||
public int gcPeriod; | |||
public int maxActivityCommits; | |||
public List<String> metricAuthorExclusions; | |||
public CommitMessageRenderer commitMessageRenderer; | |||
public transient boolean isCollectingGarbage; | |||
public Date lastGC; |
@@ -501,4 +501,5 @@ gb.reviewPatchset = review {0} patchset {1} | |||
gb.todaysActivityStats = today / {1} commits by {2} authors | |||
gb.todaysActivityNone = today / none | |||
gb.noActivityToday = there has been no activity today | |||
gb.anonymousUser= anonymous | |||
gb.anonymousUser= anonymous | |||
gb.commitMessageRenderer = commit message renderer |
@@ -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> |
@@ -79,7 +79,7 @@ public class CommitDiffPage extends RepositoryPage { | |||
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); |
@@ -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"> |
@@ -117,7 +117,7 @@ public class CommitPage extends RepositoryPage { | |||
}; | |||
add(parentsView); | |||
addFullText("fullMessage", c.getFullMessage(), true); | |||
addFullText("fullMessage", c.getFullMessage()); | |||
// git notes | |||
List<GitNote> notes = JGitUtils.getNotesOnCommit(r, c); | |||
@@ -133,8 +133,8 @@ public class CommitPage extends RepositoryPage { | |||
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)); |
@@ -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> |
@@ -52,6 +52,7 @@ import org.apache.wicket.model.util.ListModel; | |||
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 @@ public class EditRepositoryPage extends RootSubPage { | |||
} | |||
}); | |||
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 @@ public class EditRepositoryPage extends RootSubPage { | |||
return Integer.toString(index); | |||
} | |||
} | |||
} |
@@ -482,12 +482,17 @@ public abstract class RepositoryPage extends RootPage { | |||
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)); | |||
} |
@@ -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> |
@@ -92,7 +92,7 @@ public class TagPage extends RepositoryPage { | |||
} | |||
add(WicketUtils.createTimestampLabel("tagDate", when, getTimeZone(), getTimeUtils())); | |||
addFullText("fullMessage", tagRef.getFullMessage(), true); | |||
addFullText("fullMessage", tagRef.getFullMessage()); | |||
} | |||
@Override |
@@ -891,6 +891,9 @@ span.login input:focus { | |||
.commit_message { | |||
padding: 8px; | |||
} | |||
.topborder { | |||
border: solid #ddd; | |||
border-width: 1px 0px 0px; | |||
border-radius: 0px; |