Merge "Add action to log event properties"
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/ItsHookModule.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/ItsHookModule.java
index c2a6183..b25d240 100644
--- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/ItsHookModule.java
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/ItsHookModule.java
@@ -32,6 +32,7 @@
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddComment;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddStandardComment;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddVelocityComment;
+import com.googlesource.gerrit.plugins.hooks.workflow.action.LogEvent;
public class ItsHookModule extends FactoryModule {
@@ -63,5 +64,6 @@
factory(AddComment.Factory.class);
factory(AddStandardComment.Factory.class);
factory(AddVelocityComment.Factory.class);
+ factory(LogEvent.Factory.class);
}
}
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutor.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutor.java
index ce098e2..99ccf85 100644
--- a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutor.java
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutor.java
@@ -26,6 +26,7 @@
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddComment;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddStandardComment;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddVelocityComment;
+import com.googlesource.gerrit.plugins.hooks.workflow.action.LogEvent;
/**
* Executes an {@link ActionRequest}
@@ -38,15 +39,18 @@
private final AddComment.Factory addCommentFactory;
private final AddStandardComment.Factory addStandardCommentFactory;
private final AddVelocityComment.Factory addVelocityCommentFactory;
+ private final LogEvent.Factory logEventFactory;
@Inject
public ActionExecutor(ItsFacade its, AddComment.Factory addCommentFactory,
AddStandardComment.Factory addStandardCommentFactory,
- AddVelocityComment.Factory addVelocityCommentFactory) {
+ AddVelocityComment.Factory addVelocityCommentFactory,
+ LogEvent.Factory logEventFactory) {
this.its = its;
this.addCommentFactory = addCommentFactory;
this.addStandardCommentFactory = addStandardCommentFactory;
this.addVelocityCommentFactory = addVelocityCommentFactory;
+ this.logEventFactory = logEventFactory;
}
public void execute(String issue, ActionRequest actionRequest,
@@ -60,6 +64,8 @@
action = addStandardCommentFactory.create();
} else if ("add-velocity-comment".equals(name)) {
action = addVelocityCommentFactory.create();
+ } else if ("log-event".equals(name)) {
+ action = logEventFactory.create();
}
if (action == null) {
diff --git a/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/LogEvent.java b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/LogEvent.java
new file mode 100644
index 0000000..17b891d
--- /dev/null
+++ b/hooks-its/src/main/java/com/googlesource/gerrit/plugins/hooks/workflow/action/LogEvent.java
@@ -0,0 +1,88 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.hooks.workflow.action;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.hooks.workflow.ActionRequest;
+import com.googlesource.gerrit.plugins.hooks.workflow.Property;
+
+/**
+ * Dumps the event's properties to the log.
+ *
+ * This event helps when developing rules as available properties become
+ * visible.
+ */
+public class LogEvent implements Action {
+ private static final Logger log = LoggerFactory.getLogger(LogEvent.class);
+
+ private enum Level { ERROR, WARN, INFO, DEBUG };
+
+ public interface Factory {
+ LogEvent create();
+ }
+
+ @Inject
+ public LogEvent() {
+ }
+
+ private void logProperty(Level level, Property property) {
+ String message = property.toString();
+ switch (level) {
+ case ERROR:
+ log.error(message);
+ break;
+ case WARN:
+ log.warn(message);
+ break;
+ case INFO:
+ log.info(message);
+ break;
+ case DEBUG:
+ log.debug(message);
+ break;
+ default:
+ log.error("Undefined log level.");
+ }
+ }
+
+ @Override
+ public void execute(String issue, ActionRequest actionRequest,
+ Set<Property> properties) throws IOException {
+ String levelParameter = actionRequest.getParameter(1);
+ if (levelParameter != null) {
+ levelParameter = levelParameter.toLowerCase();
+ }
+ Level level = Level.INFO;
+ if ("error".equals(levelParameter)) {
+ level = Level.ERROR;
+ } else if ("warn".equals(levelParameter)) {
+ level = Level.WARN;
+ } else if ("info".equals(levelParameter)) {
+ level = Level.INFO;
+ } else if ("debug".equals(levelParameter)) {
+ level = Level.DEBUG;
+ }
+
+ for (Property property : properties) {
+ logProperty(level, property);
+ }
+ }
+}
diff --git a/hooks-its/src/main/resources/Documentation/config.md b/hooks-its/src/main/resources/Documentation/config.md
index a2c4862..b0093ed 100644
--- a/hooks-its/src/main/resources/Documentation/config.md
+++ b/hooks-its/src/main/resources/Documentation/config.md
@@ -382,6 +382,8 @@
adds a predefined standard comment for certain events
<<action-add-velocity-comment,add-velocity-comment>>::
adds a rendered Velocity template as issue comment.
+<<action-log-event,log-event>>::
+ appends the event's properties to Gerrit's log.
Further actions may be provided by 'hooks-its' based plugins.
@@ -442,6 +444,24 @@
the event's subject property, and +$change-number+ would refer to the
change's number.
+[[action-log-event]]
+Action: log-event
+^^^^^^^^^^^^^^^^^
+
+The 'log-event' action appends the event's properties to Gerrit's log.
+
+Logging happens at the info level per default, but can be overriden by
+adding the desired log level as parameter. Supported values are
+'error', 'warn', 'info', and 'debug'). So for example
+----
+action = log-event error
+----
+appends the event's properties to Gerrit's log at error level. All
+other parameters are ignored.
+
+This action is useful when testing rules or trying to refine
+conditions on rules, as it make the available properties visible.
+
[[config-legacy]]
Legacy configuration
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/testutil/LoggingMockingTestCase.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/testutil/LoggingMockingTestCase.java
index 70098e5..4878c40 100644
--- a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/testutil/LoggingMockingTestCase.java
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/testutil/LoggingMockingTestCase.java
@@ -21,18 +21,21 @@
import org.junit.After;
import java.util.Iterator;
+import org.apache.log4j.Level;
public abstract class LoggingMockingTestCase extends MockingTestCase {
private java.util.Collection<LoggingEvent> loggedEvents;
- protected final void assertLogMessageContains(String needle) {
+ protected final void assertLogMessageContains(String needle, Level level) {
LoggingEvent hit = null;
Iterator<LoggingEvent> iter = loggedEvents.iterator();
while (hit == null && iter.hasNext()) {
LoggingEvent event = iter.next();
if (event.getRenderedMessage().contains(needle)) {
- hit = event;
+ if (level == null || level.equals(event.getLevel())) {
+ hit = event;
+ }
}
}
assertNotNull("Could not find log message containing '" + needle + "'",
@@ -41,6 +44,10 @@
loggedEvents.remove(hit));
}
+ protected final void assertLogMessageContains(String needle) {
+ assertLogMessageContains(needle, null);
+ }
+
protected final void assertLogThrowableMessageContains(String needle) {
LoggingEvent hit = null;
Iterator<LoggingEvent> iter = loggedEvents.iterator();
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutorTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutorTest.java
index 7cc2597..63293e1 100644
--- a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutorTest.java
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/ActionExecutorTest.java
@@ -29,6 +29,7 @@
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddComment;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddStandardComment;
import com.googlesource.gerrit.plugins.hooks.workflow.action.AddVelocityComment;
+import com.googlesource.gerrit.plugins.hooks.workflow.action.LogEvent;
public class ActionExecutorTest extends LoggingMockingTestCase {
private Injector injector;
@@ -37,6 +38,7 @@
private AddComment.Factory addCommentFactory;
private AddStandardComment.Factory addStandardCommentFactory;
private AddVelocityComment.Factory addVelocityCommentFactory;
+ private LogEvent.Factory logEventFactory;
public void testExecuteItem() throws IOException {
ActionRequest actionRequest = createMock(ActionRequest.class);
@@ -176,6 +178,23 @@
actionExecutor.execute("4711", actionRequest, properties);
}
+ public void testLogEventDelegation() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getName()).andReturn("log-event");
+
+ Set<Property> properties = Collections.emptySet();
+
+ LogEvent logEvent = createMock(LogEvent.class);
+ expect(logEventFactory.create()).andReturn(logEvent);
+
+ logEvent.execute("4711", actionRequest, properties);
+
+ replayMocks();
+
+ ActionExecutor actionExecutor = createActionExecutor();
+ actionExecutor.execute("4711", actionRequest, properties);
+ }
+
private ActionExecutor createActionExecutor() {
return injector.getInstance(ActionExecutor.class);
}
@@ -201,6 +220,9 @@
addVelocityCommentFactory = createMock(AddVelocityComment.Factory.class);
bind(AddVelocityComment.Factory.class).toInstance(
addVelocityCommentFactory);
+
+ logEventFactory = createMock(LogEvent.Factory.class);
+ bind(LogEvent.Factory.class).toInstance(logEventFactory);
}
}
}
\ No newline at end of file
diff --git a/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/LogEventTest.java b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/LogEventTest.java
new file mode 100644
index 0000000..7d607b2
--- /dev/null
+++ b/hooks-its/src/test/java/com/googlesource/gerrit/plugins/hooks/workflow/action/LogEventTest.java
@@ -0,0 +1,161 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.plugins.hooks.workflow.action;
+
+import static org.easymock.EasyMock.expect;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.log4j.Level;
+
+import com.google.common.collect.Sets;
+import com.google.gerrit.server.config.FactoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.googlesource.gerrit.plugins.hooks.testutil.LoggingMockingTestCase;
+import com.googlesource.gerrit.plugins.hooks.workflow.ActionRequest;
+import com.googlesource.gerrit.plugins.hooks.workflow.Property;
+
+public class LogEventTest extends LoggingMockingTestCase {
+ private Injector injector;
+
+ public void testEmpty() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("");
+
+ replayMocks();
+
+ LogEvent logEvent = createLogEvent();
+ logEvent.execute("4711", actionRequest, new HashSet<Property>());
+ }
+
+ public void testLevelDefault() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("");
+
+ Set<Property> properties = Sets.newHashSet();
+ properties.add(new PropertyMock("KeyA", "ValueA", "PropertyA"));
+ replayMocks();
+
+ LogEvent logEvent = createLogEvent();
+ logEvent.execute("4711", actionRequest, properties);
+
+ assertLogMessageContains("PropertyA", Level.INFO);
+ }
+
+ public void testLevelError() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("error");
+
+ Set<Property> properties = Sets.newHashSet();
+ properties.add(new PropertyMock("KeyA", "ValueA", "PropertyA"));
+ replayMocks();
+
+ LogEvent logEvent = createLogEvent();
+ logEvent.execute("4711", actionRequest, properties);
+
+ assertLogMessageContains("PropertyA", Level.ERROR);
+ }
+
+ public void testLevelWarn() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("warn");
+
+ Set<Property> properties = Sets.newHashSet();
+ properties.add(new PropertyMock("KeyA", "ValueA", "PropertyA"));
+ replayMocks();
+
+ LogEvent logEvent = createLogEvent();
+ logEvent.execute("4711", actionRequest, properties);
+
+ assertLogMessageContains("PropertyA", Level.WARN);
+ }
+
+ public void testLevelInfo() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("info");
+
+ Set<Property> properties = Sets.newHashSet();
+ properties.add(new PropertyMock("KeyA", "ValueA", "PropertyA"));
+ replayMocks();
+
+ LogEvent logEvent = createLogEvent();
+ logEvent.execute("4711", actionRequest, properties);
+
+ assertLogMessageContains("PropertyA", Level.INFO);
+ }
+
+ public void testLevelDebug() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("debug");
+
+ Set<Property> properties = Sets.newHashSet();
+ properties.add(new PropertyMock("KeyA", "ValueA", "PropertyA"));
+ replayMocks();
+
+ LogEvent logEvent = createLogEvent();
+ logEvent.execute("4711", actionRequest, properties);
+
+ assertLogMessageContains("PropertyA", Level.DEBUG);
+ }
+
+ public void testMultipleProperties() throws IOException {
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getParameter(1)).andReturn("info");
+
+
+ Set<Property> properties = Sets.newHashSet();
+ properties.add(new PropertyMock("KeyA", "ValueA", "PropertyA"));
+ properties.add(new PropertyMock("KeyB", "ValueB", "PropertyB"));
+ properties.add(new PropertyMock("KeyC", "ValueC", "PropertyC"));
+ replayMocks();
+
+ LogEvent logEvent = createLogEvent();
+ logEvent.execute("4711", actionRequest, properties);
+
+ assertLogMessageContains("PropertyA", Level.INFO);
+ assertLogMessageContains("PropertyB", Level.INFO);
+ assertLogMessageContains("PropertyC", Level.INFO);
+ }
+
+ private LogEvent createLogEvent() {
+ return injector.getInstance(LogEvent.class);
+ }
+
+ public void setUp() throws Exception {
+ super.setUp();
+ injector = Guice.createInjector(new TestModule());
+ }
+
+ private class TestModule extends FactoryModule {
+ @Override
+ protected void configure() {
+ }
+ }
+
+ private class PropertyMock extends Property {
+ private final String toString;
+
+ public PropertyMock(String key, String value, String toString) {
+ super(key, value);
+ this.toString = toString;
+ }
+
+ public String toString() {
+ return toString;
+ }
+ }
+}
\ No newline at end of file