Allow its-* plugins to register actions of their own
More and more actions are created in the project. Each one requires
hundred of lines of modifications in its-base. Also most actions will
only be implemented in a unique its-* plugin implementation.
This change allows its-* plugin to expose new actions without requiring
the modification of its-base.
Change-Id: Ib9993cc0643f1524ce31905ebf71e1fe4994c9fa
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/ItsHookModule.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/ItsHookModule.java
index 6c68777..dc6f4a5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/ItsHookModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/ItsHookModule.java
@@ -17,6 +17,7 @@
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.config.ProjectConfigEntry;
@@ -36,6 +37,7 @@
import com.googlesource.gerrit.plugins.its.base.workflow.AddStandardComment;
import com.googlesource.gerrit.plugins.its.base.workflow.Condition;
import com.googlesource.gerrit.plugins.its.base.workflow.CreateVersionFromProperty;
+import com.googlesource.gerrit.plugins.its.base.workflow.CustomAction;
import com.googlesource.gerrit.plugins.its.base.workflow.ItsRulesProjectCacheImpl;
import com.googlesource.gerrit.plugins.its.base.workflow.LogEvent;
import com.googlesource.gerrit.plugins.its.base.workflow.Rule;
@@ -74,6 +76,7 @@
factory(CreateVersionFromProperty.Factory.class);
factory(LogEvent.Factory.class);
factory(AddPropertyToField.Factory.class);
+ DynamicMap.mapOf(binder(), CustomAction.class);
install(ItsRulesProjectCacheImpl.module());
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/Action.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/Action.java
index 338ad81..4198271 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/Action.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/Action.java
@@ -19,8 +19,7 @@
import java.util.Map;
/** Interface for actions on an issue tracking system */
-interface Action {
-
+public interface Action {
/** @return The type of this action */
ActionType getType();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
index bd42552..355d1f3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
@@ -14,6 +14,8 @@
package com.googlesource.gerrit.plugins.its.base.workflow;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.PluginName;
import com.google.gerrit.reviewdb.client.Project;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
@@ -34,6 +36,7 @@
private final LogEvent.Factory logEventFactory;
private final AddPropertyToField.Factory addPropertyToFieldFactory;
private final CreateVersionFromProperty.Factory createVersionFromPropertyFactory;
+ private final DynamicMap<CustomAction> customActions;
@Inject
public ActionExecutor(
@@ -43,7 +46,8 @@
AddSoyComment.Factory addSoyCommentFactory,
LogEvent.Factory logEventFactory,
AddPropertyToField.Factory addPropertyToFieldFactory,
- CreateVersionFromProperty.Factory createVersionFromPropertyFactory) {
+ CreateVersionFromProperty.Factory createVersionFromPropertyFactory,
+ DynamicMap<CustomAction> customActions) {
this.itsFactory = itsFactory;
this.addCommentFactory = addCommentFactory;
this.addStandardCommentFactory = addStandardCommentFactory;
@@ -51,6 +55,7 @@
this.logEventFactory = logEventFactory;
this.addPropertyToFieldFactory = addPropertyToFieldFactory;
this.createVersionFromPropertyFactory = createVersionFromPropertyFactory;
+ this.customActions = customActions;
}
private Action getAction(String actionName) {
@@ -68,19 +73,26 @@
case "create-version-from-property":
return createVersionFromPropertyFactory.create();
default:
- return null;
+ return customActions.get(PluginName.GERRIT, actionName);
}
}
+ private void execute(
+ Action action, String target, ActionRequest actionRequest, Map<String, String> properties)
+ throws IOException {
+ ItsFacade its = itsFactory.getFacade(new Project.NameKey(properties.get("project")));
+ action.execute(its, target, actionRequest, properties);
+ }
+
private void executeOnIssue(
String issue, ActionRequest actionRequest, Map<String, String> properties) {
- ItsFacade its = itsFactory.getFacade(new Project.NameKey(properties.get("project")));
try {
Action action = getAction(actionRequest.getName());
if (action == null) {
+ ItsFacade its = itsFactory.getFacade(new Project.NameKey(properties.get("project")));
its.performAction(issue, actionRequest.getUnparsed());
} else if (action.getType() == ActionType.ISSUE) {
- action.execute(its, issue, actionRequest, properties);
+ execute(action, issue, actionRequest, properties);
}
} catch (IOException e) {
log.error("Error while executing action " + actionRequest, e);
@@ -105,8 +117,7 @@
if (action.getType() != ActionType.PROJECT) {
return;
}
- ItsFacade its = itsFactory.getFacade(new Project.NameKey(properties.get("project")));
- action.execute(its, itsProject, actionRequest, properties);
+ execute(action, itsProject, actionRequest, properties);
} catch (IOException e) {
log.error("Error while executing action " + actionRequest, e);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/CustomAction.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/CustomAction.java
new file mode 100644
index 0000000..5a79650
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/CustomAction.java
@@ -0,0 +1,21 @@
+// Copyright (C) 2018 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.its.base.workflow;
+
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+
+/** Interface for actions specific to its-* plugins * */
+@ExtensionPoint
+public interface CustomAction extends Action {}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/IssueAction.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/IssueAction.java
index 230517f..37707ad 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/IssueAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/IssueAction.java
@@ -15,7 +15,7 @@
package com.googlesource.gerrit.plugins.its.base.workflow;
/** Abstraction for actions on ITS issues */
-public abstract class IssueAction implements Action {
+public abstract class IssueAction implements StandardAction {
@Override
public final ActionType getType() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ProjectAction.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ProjectAction.java
index 4c3c55b..5867377 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ProjectAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ProjectAction.java
@@ -15,7 +15,7 @@
package com.googlesource.gerrit.plugins.its.base.workflow;
/** Abstraction for actions on ITS projects */
-public abstract class ProjectAction implements Action {
+public abstract class ProjectAction implements StandardAction {
@Override
public final ActionType getType() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/StandardAction.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/StandardAction.java
new file mode 100644
index 0000000..eb23693
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/StandardAction.java
@@ -0,0 +1,18 @@
+// 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.its.base.workflow;
+
+/** Interface for actions defined by base module */
+interface StandardAction extends Action {}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
index 88cfd1a..e82ffd1 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
@@ -18,7 +18,9 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.reviewdb.client.Project;
import com.google.inject.Guice;
import com.google.inject.Injector;
@@ -31,6 +33,9 @@
import java.util.Set;
public class ActionExecutorTest extends LoggingMockingTestCase {
+
+ private static final String CUSTOM_ACTION_NAME = "custom-action-name";
+
private Injector injector;
private ItsFacade its;
@@ -41,6 +46,7 @@
private LogEvent.Factory logEventFactory;
private AddPropertyToField.Factory addPropertyToFieldFactory;
private CreateVersionFromProperty.Factory createVersionFromPropertyFactory;
+ private CustomAction customAction;
private Map<String, String> properties =
ImmutableMap.of("issue", "4711", "project", "testProject");
@@ -257,6 +263,42 @@
actionExecutor.executeOnIssue(actionRequests, properties);
}
+ public void testExecuteIssueCustomAction() throws IOException {
+ expect(customAction.getType()).andReturn(ActionType.ISSUE);
+
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getName()).andReturn(CUSTOM_ACTION_NAME);
+ expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
+ .andReturn(its);
+
+ Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
+
+ customAction.execute(its, "4711", actionRequest, properties);
+
+ replayMocks();
+
+ ActionExecutor actionExecutor = createActionExecutor();
+ actionExecutor.executeOnIssue(actionRequests, properties);
+ }
+
+ public void testExecuteProjectCustomAction() throws IOException {
+ expect(customAction.getType()).andReturn(ActionType.PROJECT);
+
+ ActionRequest actionRequest = createMock(ActionRequest.class);
+ expect(actionRequest.getName()).andReturn(CUSTOM_ACTION_NAME);
+ expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
+ .andReturn(its);
+
+ Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
+
+ customAction.execute(its, "itsTestProject", actionRequest, projectProperties);
+
+ replayMocks();
+
+ ActionExecutor actionExecutor = createActionExecutor();
+ actionExecutor.executeOnProject(actionRequests, projectProperties);
+ }
+
private ActionExecutor createActionExecutor() {
return injector.getInstance(ActionExecutor.class);
}
@@ -293,6 +335,13 @@
createVersionFromPropertyFactory = createMock(CreateVersionFromProperty.Factory.class);
bind(CreateVersionFromProperty.Factory.class).toInstance(createVersionFromPropertyFactory);
+
+ DynamicMap.mapOf(binder(), CustomAction.class);
+ customAction = createMock(CustomAction.class);
+
+ bind(CustomAction.class)
+ .annotatedWith(Exports.named(CUSTOM_ACTION_NAME))
+ .toInstance(customAction);
}
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddStandardCommentTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddStandardCommentTest.java
index 044e6a1..d695bd1 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddStandardCommentTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddStandardCommentTest.java
@@ -35,7 +35,7 @@
its.addComment("42", "Change merged");
replayMocks();
- Action action = injector.getInstance(AddStandardComment.class);
+ StandardAction action = injector.getInstance(AddStandardComment.class);
action.execute(its, "42", actionRequest, properties);
}
@@ -59,7 +59,7 @@
+ "HtTp://ExAmPlE.OrG/ChAnGe");
replayMocks();
- Action action = injector.getInstance(AddStandardComment.class);
+ StandardAction action = injector.getInstance(AddStandardComment.class);
action.execute(its, "176", actionRequest, properties);
}
@@ -71,7 +71,7 @@
its.addComment("42", "Change abandoned");
replayMocks();
- Action action = injector.getInstance(AddStandardComment.class);
+ StandardAction action = injector.getInstance(AddStandardComment.class);
action.execute(its, "42", actionRequest, properties);
}
@@ -99,7 +99,7 @@
+ "HtTp://ExAmPlE.OrG/ChAnGe");
replayMocks();
- Action action = injector.getInstance(AddStandardComment.class);
+ StandardAction action = injector.getInstance(AddStandardComment.class);
action.execute(its, "176", actionRequest, properties);
}
@@ -111,7 +111,7 @@
its.addComment("42", "Change restored");
replayMocks();
- Action action = injector.getInstance(AddStandardComment.class);
+ StandardAction action = injector.getInstance(AddStandardComment.class);
action.execute(its, "42", actionRequest, properties);
}
@@ -139,7 +139,7 @@
+ "HtTp://ExAmPlE.OrG/ChAnGe");
replayMocks();
- Action action = injector.getInstance(AddStandardComment.class);
+ StandardAction action = injector.getInstance(AddStandardComment.class);
action.execute(its, "176", actionRequest, properties);
}
@@ -151,7 +151,7 @@
its.addComment("42", "Change had a related patch set uploaded");
replayMocks();
- Action action = injector.getInstance(AddStandardComment.class);
+ StandardAction action = injector.getInstance(AddStandardComment.class);
action.execute(its, "42", actionRequest, properties);
}
@@ -176,7 +176,7 @@
+ "HtTp://ExAmPlE.OrG/ChAnGe");
replayMocks();
- Action action = injector.getInstance(AddStandardComment.class);
+ StandardAction action = injector.getInstance(AddStandardComment.class);
action.execute(its, "176", actionRequest, properties);
}