Add prefix, suffix and text field to the commentLinks.
We are planning to deprecate html option for the commentLinks.
Most common usecase for raw html matches is to make links not extend
over token boundaries or to configure the text of the link. In order
to fill the gap in functionality we are adding prefix, suffix and text
fields. The generated link will look like this:
PREFIX<a href="LINK">TEXT</a>SUFFIX
Change-Id: I0ac43e39a7484dee59928958b52cf5602abcc366
Release-Notes: Add ability to specify prefix, suffix and text fields for commentLinks of type `link`.
Forward-Compatible: checked
Google-Bug-Id: b/216788721
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 46d07df..d7ea1de 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1713,8 +1713,11 @@
link = "#/q/$1"
[commentlink "bugzilla"]
- match = "(bug\\s+#?)(\\d+)"
- link = http://bugs.example.com/show_bug.cgi?id=$2
+ match = "(^|\\s)(bug\\s+#?)(\\d+)($|\\s)"
+ link = http://bugs.example.com/show_bug.cgi?id=$3
+ prefix = $1
+ suffix = $4
+ text = $2$3
[commentlink "tracker"]
match = ([Bb]ug:\\s+)(\\d+)
@@ -1749,6 +1752,10 @@
be updated to match text formats.
+
A common pattern to match is `bug\\s+(\\d+)`.
++
+In order to better control the visual presentation of the link `prefix`,
+`suffix` and `text` is used. With the generated link html looking like:
+`prefix<a ...>text</a>suffix`.
[[commentlink.name.link]]commentlink.<name>.link::
+
@@ -1757,6 +1764,27 @@
+
The link property is used only when the html property is not present.
+[[commentlink.name.prefix]]commentlink.<name>.prefix::
++
+The text inserted before the link. Groups in the match expression may be
+accessed as `$'n'`.
++
+The link property is used only when the html property is not present.
+
+[[commentlink.name.suffix]]commentlink.<name>.suffix::
++
+The text inserted after the link. Groups in the match expression may be
+accessed as `$'n'`.
++
+The link property is used only when the html property is not present.
+
+[[commentlink.name.text]]commentlink.<name>.text::
++
+The text content of the link. Groups in the match expression may be
+accessed as `$'n'`.
++
+The link property is used only when the html property is not present.
+
[[commentlink.name.html]]commentlink.<name>.html::
+
HTML to replace the entire matched string with. If present,
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 5fd29ea..efc746a 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -3798,6 +3798,9 @@
|`link` | |The URL to direct the user to whenever the
regular expression is matched, as documented in
link:config-gerrit.html#commentlink.name.link[commentlink.name.link].
+|`prefix` |optional|Text inserted before the link.
+|`suffix` |optional|Text inserted after the link.
+|`text` |optional|Text of the link.
|`enabled` |optional|Whether the commentlink is enabled, as documented
in link:config-gerrit.html#commentlink.name.enabled[
commentlink.name.enabled]. If not set the commentlink is enabled.
@@ -3817,6 +3820,9 @@
|`link` | |The URL to direct the user to whenever the
regular expression is matched, as documented in
link:config-gerrit.html#commentlink.name.link[commentlink.name.link].
+|`prefix` |optional|Text inserted before the link.
+|`suffix` |optional|Text inserted after the link.
+|`text` |optional|Text of the link.
|`enabled` |optional|Whether the commentlink is enabled, as documented
in link:config-gerrit.html#commentlink.name.enabled[
commentlink.name.enabled]. If not set the commentlink is enabled.
diff --git a/java/com/google/gerrit/entities/StoredCommentLinkInfo.java b/java/com/google/gerrit/entities/StoredCommentLinkInfo.java
index f298782..c653a41 100644
--- a/java/com/google/gerrit/entities/StoredCommentLinkInfo.java
+++ b/java/com/google/gerrit/entities/StoredCommentLinkInfo.java
@@ -30,10 +30,38 @@
@Nullable
public abstract String getMatch();
- /** The link to replace the match with. This can only be set if html is {@code null}. */
+ /**
+ * The link to replace the match with. This can only be set if html is {@code null}.
+ *
+ * <p>The constructed link is using {@link #getLink()} {@link #getPrefix()} {@link #getSuffix()}
+ * and {@link #getText()}, and has the shape of
+ *
+ * <p>{@code PREFIX<a href="LINK">TEXT</a>SUFFIX}
+ */
@Nullable
public abstract String getLink();
+ /**
+ * The text before the link tag that the match is replaced with. This can only be set if link is
+ * not {@code null}.
+ */
+ @Nullable
+ public abstract String getPrefix();
+
+ /**
+ * The text after the link tag that the match is replaced with. This can only be set if link is
+ * not {@code null}.
+ */
+ @Nullable
+ public abstract String getSuffix();
+
+ /**
+ * The content of the link tag that the match is replaced with. This can only be set if link is
+ * not {@code null}.
+ */
+ @Nullable
+ public abstract String getText();
+
/** The html to replace the match with. This can only be set if link is {@code null}. */
@Nullable
public abstract String getHtml();
@@ -72,6 +100,9 @@
return builder(src.name)
.setMatch(src.match)
.setLink(src.link)
+ .setPrefix(src.prefix)
+ .setSuffix(src.suffix)
+ .setText(src.text)
.setHtml(src.html)
.setEnabled(enabled)
.setOverrideOnly(false)
@@ -84,6 +115,9 @@
info.name = getName();
info.match = getMatch();
info.link = getLink();
+ info.prefix = getPrefix();
+ info.suffix = getSuffix();
+ info.text = getText();
info.html = getHtml();
info.enabled = getEnabled();
return info;
@@ -97,6 +131,12 @@
public abstract Builder setLink(@Nullable String value);
+ public abstract Builder setPrefix(@Nullable String value);
+
+ public abstract Builder setSuffix(@Nullable String value);
+
+ public abstract Builder setText(@Nullable String value);
+
public abstract Builder setHtml(@Nullable String value);
public abstract Builder setEnabled(@Nullable Boolean value);
@@ -106,6 +146,9 @@
public StoredCommentLinkInfo build() {
checkArgument(getName() != null, "invalid commentlink.name");
setLink(Strings.emptyToNull(getLink()));
+ setPrefix(Strings.emptyToNull(getPrefix()));
+ setSuffix(Strings.emptyToNull(getSuffix()));
+ setText(Strings.emptyToNull(getText()));
setHtml(Strings.emptyToNull(getHtml()));
if (!getOverrideOnly()) {
checkArgument(
@@ -126,6 +169,12 @@
protected abstract String getLink();
+ protected abstract String getPrefix();
+
+ protected abstract String getSuffix();
+
+ protected abstract String getText();
+
protected abstract String getHtml();
protected abstract boolean getOverrideOnly();
diff --git a/java/com/google/gerrit/extensions/api/projects/CommentLinkInfo.java b/java/com/google/gerrit/extensions/api/projects/CommentLinkInfo.java
index 23849e4..b45fcee 100644
--- a/java/com/google/gerrit/extensions/api/projects/CommentLinkInfo.java
+++ b/java/com/google/gerrit/extensions/api/projects/CommentLinkInfo.java
@@ -17,9 +17,13 @@
import com.google.common.base.MoreObjects;
import java.util.Objects;
+/** See {@link com.google.gerrit.entities.StoredCommentLinkInfo} for field documentation. */
public class CommentLinkInfo {
public String match;
public String link;
+ public String prefix;
+ public String suffix;
+ public String text;
public String html;
public Boolean enabled; // null means true
@@ -34,6 +38,9 @@
CommentLinkInfo that = (CommentLinkInfo) o;
return Objects.equals(this.match, that.match)
&& Objects.equals(this.link, that.link)
+ && Objects.equals(this.prefix, that.prefix)
+ && Objects.equals(this.suffix, that.suffix)
+ && Objects.equals(this.text, that.text)
&& Objects.equals(this.html, that.html)
&& Objects.equals(this.enabled, that.enabled);
}
@@ -51,6 +58,9 @@
.add("name", name)
.add("match", match)
.add("link", link)
+ .add("prefix", prefix)
+ .add("suffix", suffix)
+ .add("text", text)
.add("html", html)
.add("enabled", enabled)
.toString();
diff --git a/java/com/google/gerrit/extensions/api/projects/CommentLinkInput.java b/java/com/google/gerrit/extensions/api/projects/CommentLinkInput.java
index 3aad7e1..1c964a4 100644
--- a/java/com/google/gerrit/extensions/api/projects/CommentLinkInput.java
+++ b/java/com/google/gerrit/extensions/api/projects/CommentLinkInput.java
@@ -14,14 +14,22 @@
package com.google.gerrit.extensions.api.projects;
-/*
+/**
* Input for a commentlink configuration on a project.
+ *
+ * <p>See {@link com.google.gerrit.entities.StoredCommentLinkInfo} for additional details.
*/
public class CommentLinkInput {
/** A JavaScript regular expression to match positions to be replaced with a hyperlink. */
public String match;
/** The URL to direct the user to whenever the regular expression is matched. */
public String link;
+ /** Text inserted before the link if the regular expression is matched. */
+ public String prefix;
+ /** Text inserted after the link if the regular expression is matched. */
+ public String suffix;
+ /** Text of the link. */
+ public String text;
/** Whether the commentlink is enabled. */
public Boolean enabled;
}
diff --git a/java/com/google/gerrit/server/cache/serialize/entities/StoredCommentLinkInfoSerializer.java b/java/com/google/gerrit/server/cache/serialize/entities/StoredCommentLinkInfoSerializer.java
index a7a84f7..5aa7a2a 100644
--- a/java/com/google/gerrit/server/cache/serialize/entities/StoredCommentLinkInfoSerializer.java
+++ b/java/com/google/gerrit/server/cache/serialize/entities/StoredCommentLinkInfoSerializer.java
@@ -27,6 +27,9 @@
return StoredCommentLinkInfo.builder(proto.getName())
.setMatch(emptyToNull(proto.getMatch()))
.setLink(emptyToNull(proto.getLink()))
+ .setPrefix(emptyToNull(proto.getPrefix()))
+ .setSuffix(emptyToNull(proto.getSuffix()))
+ .setText(emptyToNull(proto.getText()))
.setHtml(emptyToNull(proto.getHtml()))
.setEnabled(proto.getEnabled())
.setOverrideOnly(proto.getOverrideOnly())
@@ -38,6 +41,9 @@
.setName(autoValue.getName())
.setMatch(nullToEmpty(autoValue.getMatch()))
.setLink(nullToEmpty(autoValue.getLink()))
+ .setPrefix(nullToEmpty(autoValue.getPrefix()))
+ .setSuffix(nullToEmpty(autoValue.getSuffix()))
+ .setText(nullToEmpty(autoValue.getText()))
.setHtml(nullToEmpty(autoValue.getHtml()))
.setEnabled(Optional.ofNullable(autoValue.getEnabled()).orElse(true))
.setOverrideOnly(autoValue.getOverrideOnly())
diff --git a/java/com/google/gerrit/server/project/ProjectConfig.java b/java/com/google/gerrit/server/project/ProjectConfig.java
index 3e43cd3..47b0a53 100644
--- a/java/com/google/gerrit/server/project/ProjectConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectConfig.java
@@ -133,6 +133,9 @@
public static final String KEY_MATCH = "match";
private static final String KEY_HTML = "html";
public static final String KEY_LINK = "link";
+ public static final String KEY_PREFIX = "prefix";
+ public static final String KEY_SUFFIX = "suffix";
+ public static final String KEY_TEXT = "text";
public static final String KEY_ENABLED = "enabled";
public static final String PROJECT_CONFIG = "project.config";
@@ -328,6 +331,10 @@
}
String link = cfg.getString(COMMENTLINK, name, KEY_LINK);
+ String linkPrefix = cfg.getString(COMMENTLINK, name, KEY_PREFIX);
+ String linkSuffix = cfg.getString(COMMENTLINK, name, KEY_SUFFIX);
+ String linkText = cfg.getString(COMMENTLINK, name, KEY_TEXT);
+
String html = cfg.getString(COMMENTLINK, name, KEY_HTML);
boolean hasHtml = !Strings.isNullOrEmpty(html);
@@ -352,6 +359,9 @@
return StoredCommentLinkInfo.builder(name)
.setMatch(match)
.setLink(link)
+ .setPrefix(linkPrefix)
+ .setSuffix(linkSuffix)
+ .setText(linkText)
.setHtml(html)
.setEnabled(enabled)
.setOverrideOnly(false)
@@ -1377,6 +1387,15 @@
if (!Strings.isNullOrEmpty(cm.getLink())) {
rc.setString(COMMENTLINK, cm.getName(), KEY_LINK, cm.getLink());
}
+ if (!Strings.isNullOrEmpty(cm.getPrefix())) {
+ rc.setString(COMMENTLINK, cm.getName(), KEY_PREFIX, cm.getPrefix());
+ }
+ if (!Strings.isNullOrEmpty(cm.getSuffix())) {
+ rc.setString(COMMENTLINK, cm.getName(), KEY_SUFFIX, cm.getSuffix());
+ }
+ if (!Strings.isNullOrEmpty(cm.getText())) {
+ rc.setString(COMMENTLINK, cm.getName(), KEY_TEXT, cm.getText());
+ }
if (cm.getEnabled() != null && !cm.getEnabled()) {
rc.setBoolean(COMMENTLINK, cm.getName(), KEY_ENABLED, cm.getEnabled());
}
diff --git a/java/com/google/gerrit/server/restapi/project/PutConfig.java b/java/com/google/gerrit/server/restapi/project/PutConfig.java
index 30d667c..d4077c8 100644
--- a/java/com/google/gerrit/server/restapi/project/PutConfig.java
+++ b/java/com/google/gerrit/server/restapi/project/PutConfig.java
@@ -18,6 +18,9 @@
import static com.google.gerrit.server.project.ProjectConfig.KEY_ENABLED;
import static com.google.gerrit.server.project.ProjectConfig.KEY_LINK;
import static com.google.gerrit.server.project.ProjectConfig.KEY_MATCH;
+import static com.google.gerrit.server.project.ProjectConfig.KEY_PREFIX;
+import static com.google.gerrit.server.project.ProjectConfig.KEY_SUFFIX;
+import static com.google.gerrit.server.project.ProjectConfig.KEY_TEXT;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
@@ -300,6 +303,15 @@
Config cfg = new Config();
cfg.setString(COMMENTLINK, name, KEY_MATCH, value.match);
cfg.setString(COMMENTLINK, name, KEY_LINK, value.link);
+ if (!Strings.isNullOrEmpty(value.prefix)) {
+ cfg.setString(COMMENTLINK, name, KEY_PREFIX, value.prefix);
+ }
+ if (!Strings.isNullOrEmpty(value.suffix)) {
+ cfg.setString(COMMENTLINK, name, KEY_SUFFIX, value.suffix);
+ }
+ if (!Strings.isNullOrEmpty(value.text)) {
+ cfg.setString(COMMENTLINK, name, KEY_TEXT, value.text);
+ }
cfg.setBoolean(COMMENTLINK, name, KEY_ENABLED, value.enabled == null || value.enabled);
projectConfig.addCommentLinkSection(ProjectConfig.buildCommentLink(cfg, name, false));
} else {
diff --git a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
index 58d1628..f997c77 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -788,6 +788,39 @@
}
@Test
+ public void projectConfigUsesLocallySetCommentlinksWithOptionalFields() throws Exception {
+ ConfigInput input = new ConfigInput();
+ CommentLinkInput bugzillaInput = new CommentLinkInput();
+ String match = "(^|\\\\s)(bug\\\\s+#?)(\\\\d+)($|\\\\s)";
+ String link = "http://bugzilla.example.com/?id=$3";
+ String prefix = "$1";
+ String suffix = "$4";
+ String text = "$2$3";
+ bugzillaInput.match = match;
+ bugzillaInput.link = link;
+ bugzillaInput.prefix = prefix;
+ bugzillaInput.suffix = suffix;
+ bugzillaInput.text = text;
+ addCommentLink(input, BUGZILLA, bugzillaInput);
+ addCommentLink(input, JIRA, JIRA_MATCH, JIRA_LINK);
+
+ ConfigInfo info = setConfig(project, input);
+
+ Map<String, CommentLinkInfo> expected = new HashMap<>();
+ CommentLinkInfo bugzillaInfo = new CommentLinkInfo();
+ bugzillaInfo.name = BUGZILLA;
+ bugzillaInfo.match = match;
+ bugzillaInfo.link = link;
+ bugzillaInfo.prefix = prefix;
+ bugzillaInfo.suffix = suffix;
+ bugzillaInfo.text = text;
+ expected.put(BUGZILLA, bugzillaInfo);
+ expected.put(JIRA, commentLinkInfo(JIRA, JIRA_MATCH, JIRA_LINK));
+ assertCommentLinks(info, expected);
+ assertCommentLinks(getConfig(), expected);
+ }
+
+ @Test
@GerritConfig(name = "commentlink.bugzilla.match", value = BUGZILLA_MATCH)
@GerritConfig(name = "commentlink.bugzilla.link", value = BUGZILLA_LINK)
public void projectConfigUsesCommentLinksFromGlobalAndLocal() throws Exception {
diff --git a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
index 5231c00..c8cc713 100644
--- a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
+++ b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
@@ -702,15 +702,21 @@
.add(
"project.config",
"[commentlink \"bugzilla\"]\n"
- + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
- + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2")
+ + "\tmatch = \"(^|\\\\s)(bug\\\\s+#?)(\\\\d+)($|\\\\s)\"\n"
+ + "\tlink = http://bugs.example.com/show_bug.cgi?id=$3\n"
+ + "\tprefix = $1\n"
+ + "\ttext = $2$3\n"
+ + "\tsuffix = $4\n")
.create();
ProjectConfig cfg = read(rev);
assertThat(cfg.getCommentLinkSections())
.containsExactly(
StoredCommentLinkInfo.builder("bugzilla")
- .setMatch("(bug\\s+#?)(\\d+)")
- .setLink("http://bugs.example.com/show_bug.cgi?id=$2")
+ .setMatch("(^|\\s)(bug\\s+#?)(\\d+)($|\\s)")
+ .setLink("http://bugs.example.com/show_bug.cgi?id=$3")
+ .setPrefix("$1")
+ .setSuffix("$4")
+ .setText("$2$3")
.setOverrideOnly(false)
.build());
}
diff --git a/proto/cache.proto b/proto/cache.proto
index 1c37567..83c2ce2 100644
--- a/proto/cache.proto
+++ b/proto/cache.proto
@@ -533,14 +533,17 @@
}
// Serialized form of com.google.gerrit.entities.StoredCommentLinkInfo.
-// Next ID: 7
+// Next ID: 10
message StoredCommentLinkInfoProto {
string name = 1;
string match = 2;
- string link = 3;
string html = 4;
bool enabled = 5;
bool override_only = 6;
+ string link = 3;
+ string prefix = 7;
+ string suffix = 8;
+ string text = 9;
}
// Serialized form of com.google.gerrit.entities.CachedProjectConfigProto.