Add link formatting to Velocity comments
For example the rule
[rule "formatLinkSampleRule"]
event-type = comment-added
action = add-velocity-comment inline Comment for change $change-number added. See ${its.formatLink($change-url)}
would format a link to the event's change-url in the its' syntax.
Change-Id: Ic3b4a13913309719c34ed1e66a9acdf246096522
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityComment.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityComment.java
index 45afb65..e2db316 100644
--- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityComment.java
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityComment.java
@@ -76,6 +76,9 @@
}
}
}
+
+ velocityContext.put("its", new VelocityAdapterItsFacade(its));
+
return velocityContext;
}
@@ -114,4 +117,41 @@
its.addComment(issue, comment);
}
}
+
+ /**
+ * Adapter for ItsFacade to be used through Velocity
+ */
+ // Although we'd prefer to keep this class private, Velocity will only pick
+ // it up, if it is public.
+ public class VelocityAdapterItsFacade {
+
+ private final ItsFacade its;
+
+ private VelocityAdapterItsFacade(ItsFacade its) {
+ this.its = its;
+ }
+
+ /**
+ * Format a link to a URL in the used Its' syntax.
+ *
+ * @param url URL to link to
+ * @param caption Text used to represent the link
+ * @return Link to the given URL in the used Its' syntax.
+ */
+ public String formatLink(String url, String caption) {
+ return its.createLinkForWebui(url, caption);
+ }
+
+ /**
+ * Format a link to an URL.
+ * <p>
+ * The provided URL is used as caption for the formatted link.
+ *
+ * @param url URL to link to
+ * @return Link to the given URL in the used Its' syntax.
+ */
+ public String formatLink(String url) {
+ return its.createLinkForWebui(url, url);
+ }
+ }
}
diff --git a/hooks-its/src/main/resources/Documentation/config.md b/hooks-its/src/main/resources/Documentation/config.md
index b0093ed..2745d9c 100644
--- a/hooks-its/src/main/resources/Documentation/config.md
+++ b/hooks-its/src/main/resources/Documentation/config.md
@@ -444,6 +444,34 @@
the event's subject property, and +$change-number+ would refer to the
change's number.
+Additionally, the context's 'its' property provides an object that
+allows to format links using the its' syntax:
+
+'formatLink( url )'::
+ Formats a link to a url.
+ +
+ So for example upon adding a comment to a change, the following rule
+ formats a link to the change:
++
+----
+[rule "formatLinkSampleRule"]
+ event-type = comment-added
+ action = add-velocity-comment inline Comment for change $change-number added. See ${its.formatLink($change-url)}
+----
+
+'formatLink( url, caption )'::
+ Formats a link to a url using 'caption' to represent the url.
+ +
+ So for example upon adding a comment to a change, the following rule
+ formats a link to the change using the change number as link
+ capition:
++
+----
+[rule "formatLinkSampleRule"]
+ event-type = comment-added
+ action = add-velocity-comment inline Comment for change ${its.formatLink($change-url, $change-number)} added.
+-----
+
[[action-log-event]]
Action: log-event
^^^^^^^^^^^^^^^^^
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityCommentTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityCommentTest.java
index 5d6b71c..a7de371 100644
--- a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityCommentTest.java
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/AddVelocityCommentTest.java
@@ -23,6 +23,7 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@@ -43,6 +44,7 @@
import com.googlesource.gerrit.plugins.hooks.testutil.LoggingMockingTestCase;
import com.googlesource.gerrit.plugins.hooks.workflow.ActionRequest;
import com.googlesource.gerrit.plugins.hooks.workflow.Property;
+import com.googlesource.gerrit.plugins.hooks.workflow.action.AddVelocityComment.VelocityAdapterItsFacade;
public class AddVelocityCommentTest extends LoggingMockingTestCase {
private Injector injector;
@@ -199,6 +201,79 @@
context.get("reason"));
}
+ public void testItsWrapperFormatLink1Parameter() throws IOException,
+ SecurityException, NoSuchMethodException, IllegalArgumentException,
+ IllegalAccessException, InvocationTargetException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("inline");
+ expect(actionRequest.getParameters()).andReturn(
+ new String[] {"inline", "Simple-Text"});
+
+ IAnswer<Boolean> answer = new VelocityWriterFiller("Simple-Text");
+ Capture<VelocityContext> contextCapture = new Capture<VelocityContext>();
+ expect(velocityRuntime.evaluate(capture(contextCapture),
+ (Writer)anyObject(), (String)anyObject(), eq("Simple-Text")))
+ .andAnswer(answer);
+
+ its.addComment("4711", "Simple-Text");
+
+ expect(its.createLinkForWebui("http://www.example.org/",
+ "http://www.example.org/")) .andReturn("Formatted Link");
+
+ replayMocks();
+
+ AddVelocityComment addVelocityComment = createAddVelocityComment();
+ addVelocityComment.execute("4711", actionRequest, new HashSet<Property>());
+
+ VelocityContext context = contextCapture.getValue();
+ Object itsAdapterObj = context.get("its");
+ assertNotNull("its property is null", itsAdapterObj);
+ assertTrue("Its is not a VelocityAdapterItsFacade instance",
+ itsAdapterObj instanceof VelocityAdapterItsFacade);
+ VelocityAdapterItsFacade itsAdapter =
+ (VelocityAdapterItsFacade) itsAdapterObj;
+ String formattedLink = itsAdapter.formatLink("http://www.example.org/");
+ assertEquals("Result of formatLink does not match", "Formatted Link",
+ formattedLink);
+ }
+
+ public void testItsWrapperFormatLink2Parameters() throws IOException,
+ SecurityException, NoSuchMethodException, IllegalArgumentException,
+ IllegalAccessException, InvocationTargetException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("inline");
+ expect(actionRequest.getParameters()).andReturn(
+ new String[] {"inline", "Simple-Text"});
+
+ IAnswer<Boolean> answer = new VelocityWriterFiller("Simple-Text");
+ Capture<VelocityContext> contextCapture = new Capture<VelocityContext>();
+ expect(velocityRuntime.evaluate(capture(contextCapture),
+ (Writer)anyObject(), (String)anyObject(), eq("Simple-Text")))
+ .andAnswer(answer);
+
+ its.addComment("4711", "Simple-Text");
+
+ expect(its.createLinkForWebui("http://www.example.org/", "Caption"))
+ .andReturn("Formatted Link");
+
+ replayMocks();
+
+ AddVelocityComment addVelocityComment = createAddVelocityComment();
+ addVelocityComment.execute("4711", actionRequest, new HashSet<Property>());
+
+ VelocityContext context = contextCapture.getValue();
+ Object itsAdapterObj = context.get("its");
+ assertNotNull("its property is null", itsAdapterObj);
+ assertTrue("Its is not a VelocityAdapterItsFacade instance",
+ itsAdapterObj instanceof VelocityAdapterItsFacade);
+ VelocityAdapterItsFacade itsAdapter =
+ (VelocityAdapterItsFacade) itsAdapterObj;
+ String formattedLink = itsAdapter.formatLink("http://www.example.org/",
+ "Caption");
+ assertEquals("Result of formatLink does not match", "Formatted Link",
+ formattedLink);
+ }
+
public void testWarnTemplateNotFound() throws IOException {
ActionRequest actionRequest = createMock(ActionRequest.class);
expect(actionRequest.getParameter(1)).andReturn("non-existing-template");