Merge changes I99bb4320,I7d5d74f1,Ic3b4a139
* changes:
Hide Condition's getValue
Add handling of DraftPublishedEvent
Add link formatting to Velocity comments
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractor.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractor.java
index fe69773..77ef563 100644
--- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractor.java
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractor.java
@@ -26,6 +26,7 @@
import com.google.gerrit.server.events.ChangeMergedEvent;
import com.google.gerrit.server.events.ChangeRestoredEvent;
import com.google.gerrit.server.events.CommentAddedEvent;
+import com.google.gerrit.server.events.DraftPublishedEvent;
import com.google.gerrit.server.events.PatchSetCreatedEvent;
import com.google.gerrit.server.events.RefUpdatedEvent;
import com.google.inject.Inject;
@@ -104,6 +105,18 @@
event.patchSet.revision, patchSetId);
}
+ private Map<String,Set<String>> extractFrom(DraftPublishedEvent event,
+ Set<Property> common) {
+ common.add(propertyFactory.create("event-type", event.type));
+ common.addAll(propertyAttributeExtractor.extractFrom(event.change));
+ common.addAll(propertyAttributeExtractor.extractFrom(event.patchSet));
+ common.addAll(propertyAttributeExtractor.extractFrom(event.uploader, "uploader"));
+ PatchSet.Id patchSetId = newPatchSetId(event.change.number,
+ event.patchSet.number);
+ return issueExtractor.getIssueIds(event.change.project,
+ event.patchSet.revision, patchSetId);
+ }
+
private Map<String,Set<String>> extractFrom(RefUpdatedEvent event,
Set<Property> common) {
common.add(propertyFactory.create("event-type", event.type));
@@ -199,6 +212,8 @@
associations = extractFrom((ChangeRestoredEvent) event, common);
} else if (event instanceof CommentAddedEvent) {
associations = extractFrom((CommentAddedEvent) event, common);
+ } else if (event instanceof DraftPublishedEvent) {
+ associations = extractFrom((DraftPublishedEvent) event, common);
} else if (event instanceof PatchSetCreatedEvent) {
associations = extractFrom((PatchSetCreatedEvent) event, common);
} else if (event instanceof RefUpdatedEvent) {
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/Condition.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/Condition.java
index 1bb1564..47aae91 100644
--- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/Condition.java
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/Condition.java
@@ -63,10 +63,6 @@
return key;
}
- public Set<String> getValues() {
- return values;
- }
-
/**
* Checks whether or not the Condition matches the given set of properties
*
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..2593171 100644
--- a/hooks-its/src/main/resources/Documentation/config.md
+++ b/hooks-its/src/main/resources/Documentation/config.md
@@ -168,6 +168,7 @@
* <<event-properties-ChangeMergedEvent,ChangeMergedEvent>>
* <<event-properties-ChangeRestoredEvent,ChangeRestoredEvent>>
* <<event-properties-CommentAddedEvent,CommentAddedEvent>>
+* <<event-properties-DraftPublishedEvent,DraftPublishedEvent>>
* <<event-properties-PatchSetCreatedEvent,PatchSetCreatedEvent>>
* <<event-properties-RefUpdatedEvent,RefUpdatedEvent>>
* <<event-properties-change,Common properties for events on a change>>
@@ -270,6 +271,19 @@
added for, and it's most recent <<event-properties-patch-set,patch
set>>.
+[[event-properties-DraftPublishedEvent]]
+DraftPublishedEvent
+^^^^^^^^^^^^^^^^^^^
+
+'event'::
+ +com.google.gerrit.server.events.DraftPublishedEvent+
+'event-type'::
+ +draft-published+
+
+In addition to the above properties, the event also provides
+properties for the uploaded <<event-properties-patch-set,patch set>>,
+and the <<event-properties-change,change>> it belongs to.
+
[[event-properties-PatchSetCreatedEvent]]
PatchSetCreatedEvent
^^^^^^^^^^^^^^^^^^^
@@ -444,6 +458,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/util/PropertyExtractorTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractorTest.java
index 421038d..dda4173 100644
--- a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractorTest.java
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/util/PropertyExtractorTest.java
@@ -33,6 +33,7 @@
import com.google.gerrit.server.events.ChangeMergedEvent;
import com.google.gerrit.server.events.ChangeRestoredEvent;
import com.google.gerrit.server.events.CommentAddedEvent;
+import com.google.gerrit.server.events.DraftPublishedEvent;
import com.google.gerrit.server.events.PatchSetCreatedEvent;
import com.google.gerrit.server.events.RefUpdatedEvent;
import com.google.inject.Guice;
@@ -276,6 +277,41 @@
eventHelper(event, "CommentAddedEvent", "comment-added", common, true);
}
+ public void testDraftPublishedEvent() {
+ DraftPublishedEvent event = new DraftPublishedEvent();
+
+ ChangeAttribute changeAttribute = createMock(ChangeAttribute.class);
+ event.change = changeAttribute;
+ Property propertyChange = createMock(Property.class);
+ expect(propertyAttributeExtractor.extractFrom(changeAttribute))
+ .andReturn(Sets.newHashSet(propertyChange));
+
+ AccountAttribute accountAttribute = createMock(AccountAttribute.class);
+ event.uploader = accountAttribute;
+ Property propertySubmitter = createMock(Property.class);
+ expect(propertyAttributeExtractor.extractFrom(accountAttribute,
+ "uploader")).andReturn(Sets.newHashSet(propertySubmitter));
+
+ PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class);
+ event.patchSet = patchSetAttribute;
+ Property propertyPatchSet = createMock(Property.class);
+ expect(propertyAttributeExtractor.extractFrom(patchSetAttribute))
+ .andReturn(Sets.newHashSet(propertyPatchSet));
+
+ changeAttribute.project = "testProject";
+ changeAttribute.number = "176";
+ patchSetAttribute.revision = "testRevision";
+ patchSetAttribute.number = "3";
+
+ Set<Property> common = Sets.newHashSet();
+ common.add(propertyChange);
+ common.add(propertySubmitter);
+ common.add(propertyPatchSet);
+
+ eventHelper(event, "DraftPublishedEvent", "draft-published", common,
+ true);
+ }
+
public void testPatchSetCreatedEvent() {
PatchSetCreatedEvent event = new PatchSetCreatedEvent();
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ConditionTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ConditionTest.java
index d672ab7..857f9e8 100644
--- a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ConditionTest.java
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ConditionTest.java
@@ -17,10 +17,8 @@
import java.util.Collection;
import java.util.Collections;
-import java.util.Set;
import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
import com.google.gerrit.server.config.FactoryModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -29,36 +27,11 @@
public class ConditionTest extends LoggingMockingTestCase {
private Injector injector;
- public void testSimpleValue() {
- Condition condition = createCondition("testKey", "testValue");
- assertEquals("key not matching 'testKey'", "testKey", condition.getKey());
- Set<String> expectedValues = Sets.newHashSet();
- expectedValues.add("testValue");
- assertEquals("values do not match", expectedValues, condition.getValues());
- }
-
public void testGetKeyNull() {
Condition condition = new Condition(null, "testValues");
assertNull("key is not null", condition.getKey());
}
- public void testGetValuesNull() {
- Condition condition = createCondition("testKey", null);
- Set<String> values = condition.getValues();
- assertNotNull("values is null", values);
- assertTrue("values is not empty", values.isEmpty());
- }
-
- public void testOredValue() {
- Condition condition = createCondition("testKey", "value1,value2,value3");
- assertEquals("key not matching 'testKey'", "testKey", condition.getKey());
- Set<String> expectedValues = Sets.newLinkedHashSet();
- expectedValues.add("value1");
- expectedValues.add("value2");
- expectedValues.add("value3");
- assertEquals("values do not match", expectedValues, condition.getValues());
- }
-
public void testIsMetBySimple() {
Condition condition = createCondition("testKey", "testValue");
@@ -199,16 +172,6 @@
assertTrue("isMetBy gave false", condition.isMetBy(properties));
}
- public void testUnmodifiableValue() {
- Condition condition = createCondition("testKey", "testValue");
- Set<String> values = condition.getValues();
- try {
- values.add("value2");
- fail("value is not unmodifyable");
- } catch (UnsupportedOperationException e) {
- }
- }
-
private Condition createCondition(String key, String value) {
Condition.Factory factory = injector.getInstance(Condition.Factory.class);
return factory.create(key, value);
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");