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); }