Merge branch 'stable-3.1' * stable-3.1: Format files with google-java-format Change-Id: I5617d4ebf7b283a334a77c79fdb7379dd1e87896
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 dc6f4a5..8835389 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
@@ -38,9 +38,11 @@ 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.FireEventOnCommits; 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; +import com.googlesource.gerrit.plugins.its.base.workflow.commit_collector.SinceLastTagCommitCollector; import java.nio.file.Path; public class ItsHookModule extends FactoryModule { @@ -78,6 +80,8 @@ factory(AddPropertyToField.Factory.class); DynamicMap.mapOf(binder(), CustomAction.class); install(ItsRulesProjectCacheImpl.module()); + factory(FireEventOnCommits.Factory.class); + factory(SinceLastTagCommitCollector.Factory.class); } @Provides
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java index 08f73c5..20c6c4a 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java
@@ -94,16 +94,17 @@ } public boolean isEnabled(Project.NameKey projectNK, String refName) { - ProjectState projectState = projectCache.get(projectNK); - if (projectState == null) { + Optional<ProjectState> projectState = projectCache.get(projectNK); + if (!projectState.isPresent()) { log.error( "Failed to check if {} is enabled for project {}: Project not found", pluginName, projectNK.get()); return false; } - return isEnforcedByAnyParentProject(refName, projectState) - || (isEnabledForProject(projectState) && isEnabledForBranch(projectState, refName)); + return isEnforcedByAnyParentProject(refName, projectState.get()) + || (isEnabledForProject(projectState.get()) + && isEnabledForBranch(projectState.get(), refName)); } private boolean isEnforcedByAnyParentProject(String refName, ProjectState projectState) { @@ -147,12 +148,14 @@ // Project association public Optional<String> getItsProjectName(Project.NameKey projectNK) { - ProjectState projectState = projectCache.get(projectNK); - if (projectState == null) { + Optional<ProjectState> projectState = projectCache.get(projectNK); + if (!projectState.isPresent()) { return Optional.empty(); } return Optional.ofNullable( - pluginCfgFactory.getFromProjectConfig(projectState, pluginName).getString("its-project")); + pluginCfgFactory + .getFromProjectConfig(projectState.get(), pluginName) + .getString("its-project")); } // Issue association -------------------------------------------------------- @@ -266,7 +269,7 @@ private List<CommentLinkInfo> getCommentLinkInfo(final String commentlinkName) { NameKey projectName = currentProjectName.get(); if (projectName != null) { - List<CommentLinkInfo> commentlinks = projectCache.get(projectName).getCommentLinks(); + List<CommentLinkInfo> commentlinks = projectCache.get(projectName).get().getCommentLinks(); return commentlinks.stream() .filter(input -> input.name.equals(commentlinkName)) .collect(toList());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractor.java index 926db56..bf9dc0c 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractor.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractor.java
@@ -34,6 +34,7 @@ import com.google.gerrit.server.events.WorkInProgressStateChangedEvent; import com.google.inject.Inject; import com.googlesource.gerrit.plugins.its.base.workflow.RefEventProperties; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -230,16 +231,33 @@ associations = extractFrom((WorkInProgressStateChangedEvent) event, common); } - Set<Map<String, String>> ret = new HashSet<>(); - if (associations != null) { - for (Entry<String, Set<String>> assoc : associations.entrySet()) { - Map<String, String> properties = new HashMap<>(); - properties.put("issue", assoc.getKey()); - properties.put("association", String.join(" ", assoc.getValue())); - properties.putAll(common); - ret.add(properties); - } + Set<Map<String, String>> issuesProperties = extractIssuesProperties(common, associations); + + Map<String, String> projectProperties = new HashMap<>(common); + projectProperties.put("source", "gerrit"); + return new RefEventProperties(projectProperties, issuesProperties); + } + + public Set<Map<String, String>> extractIssuesProperties( + Map<String, String> commonProperties, Map<String, Set<String>> associations) { + if (associations == null) { + return Collections.emptySet(); } - return new RefEventProperties(common, ret); + + Set<Map<String, String>> issuesProperties = new HashSet<>(); + Map<String, String> completedCommonProperties = new HashMap<>(commonProperties); + if (!completedCommonProperties.containsKey("source")) { + completedCommonProperties.put("source", "its"); + } + + for (Entry<String, Set<String>> assoc : associations.entrySet()) { + Map<String, String> properties = new HashMap<>(); + properties.put("issue", assoc.getKey()); + properties.put("association", String.join(" ", assoc.getValue())); + properties.putAll(completedCommonProperties); + issuesProperties.add(properties); + } + + return issuesProperties; } }
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 b8682ad..44f5d73 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
@@ -36,6 +36,7 @@ private final LogEvent.Factory logEventFactory; private final AddPropertyToField.Factory addPropertyToFieldFactory; private final CreateVersionFromProperty.Factory createVersionFromPropertyFactory; + private final FireEventOnCommits.Factory fireEventOnCommitsFactory; private final DynamicMap<CustomAction> customActions; @Inject @@ -47,6 +48,7 @@ LogEvent.Factory logEventFactory, AddPropertyToField.Factory addPropertyToFieldFactory, CreateVersionFromProperty.Factory createVersionFromPropertyFactory, + FireEventOnCommits.Factory fireEventOnCommitsFactory, DynamicMap<CustomAction> customActions) { this.itsFactory = itsFactory; this.addCommentFactory = addCommentFactory; @@ -55,6 +57,7 @@ this.logEventFactory = logEventFactory; this.addPropertyToFieldFactory = addPropertyToFieldFactory; this.createVersionFromPropertyFactory = createVersionFromPropertyFactory; + this.fireEventOnCommitsFactory = fireEventOnCommitsFactory; this.customActions = customActions; } @@ -72,6 +75,8 @@ return addPropertyToFieldFactory.create(); case "create-version-from-property": return createVersionFromPropertyFactory.create(); + case "fire-event-on-commits": + return fireEventOnCommitsFactory.create(); default: return customActions.get(PluginName.GERRIT, actionName); }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommits.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommits.java new file mode 100644 index 0000000..7ade76b --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommits.java
@@ -0,0 +1,89 @@ +// 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.inject.Inject; +import com.googlesource.gerrit.plugins.its.base.its.ItsFacade; +import com.googlesource.gerrit.plugins.its.base.util.IssueExtractor; +import com.googlesource.gerrit.plugins.its.base.util.PropertyExtractor; +import com.googlesource.gerrit.plugins.its.base.workflow.commit_collector.CommitCollector; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** Fires the triggering event on collected past commits */ +public class FireEventOnCommits extends ProjectAction { + + public interface Factory { + FireEventOnCommits create(); + } + + private final PropertyExtractor propertyExtractor; + private final IssueExtractor issueExtractor; + private final RuleBase ruleBase; + private final ActionExecutor actionExecutor; + private final FireEventOnCommitsParametersExtractor parametersExtractor; + + @Inject + public FireEventOnCommits( + PropertyExtractor propertyExtractor, + IssueExtractor issueExtractor, + RuleBase ruleBase, + ActionExecutor actionExecutor, + FireEventOnCommitsParametersExtractor parametersExtractor) { + this.propertyExtractor = propertyExtractor; + this.issueExtractor = issueExtractor; + this.ruleBase = ruleBase; + this.actionExecutor = actionExecutor; + this.parametersExtractor = parametersExtractor; + } + + @Override + public void execute( + ItsFacade its, String itsProject, ActionRequest actionRequest, Map<String, String> properties) + throws IOException { + Optional<FireEventOnCommitsParameters> extractedParameters = + parametersExtractor.extract(actionRequest, properties); + if (!extractedParameters.isPresent()) { + return; + } + + CommitCollector commitCollector = extractedParameters.get().getCommitCollector(); + String projectName = extractedParameters.get().getProjectName(); + + Set<Map<String, String>> issuesProperties = + commitCollector.collect(properties).stream() + .map(commitId -> issueExtractor.getIssueIds(projectName, commitId)) + .flatMap(Stream::of) + .map( + associations -> propertyExtractor.extractIssuesProperties(properties, associations)) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + issuesProperties.forEach(this::doExecute); + } + + private void doExecute(Map<String, String> issueProperties) { + Collection<ActionRequest> actions = ruleBase.actionRequestsFor(issueProperties); + if (actions.isEmpty()) { + return; + } + actionExecutor.executeOnIssue(actions, issueProperties); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParameters.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParameters.java new file mode 100644 index 0000000..d6ee4db --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParameters.java
@@ -0,0 +1,41 @@ +// 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.googlesource.gerrit.plugins.its.base.workflow.commit_collector.CommitCollector; + +/** Parameters needed by {@link FireEventOnCommits} action */ +public class FireEventOnCommitsParameters { + + private final CommitCollector commitCollector; + private final String projectName; + + public FireEventOnCommitsParameters(CommitCollector commitCollector, String projectName) { + this.commitCollector = commitCollector; + this.projectName = projectName; + } + + /** + * @return The collector that will be used to collect the commits on which the event will be fired + */ + public CommitCollector getCommitCollector() { + return commitCollector; + } + + /** @return The name of the project from which the commits will be collected */ + public String getProjectName() { + return projectName; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParametersExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParametersExtractor.java new file mode 100644 index 0000000..d7ae586 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParametersExtractor.java
@@ -0,0 +1,78 @@ +// 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.common.base.Strings; +import com.googlesource.gerrit.plugins.its.base.workflow.commit_collector.CommitCollector; +import com.googlesource.gerrit.plugins.its.base.workflow.commit_collector.SinceLastTagCommitCollector; +import java.util.Arrays; +import java.util.Map; +import java.util.Optional; +import javax.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FireEventOnCommitsParametersExtractor { + + private static final Logger log = + LoggerFactory.getLogger(FireEventOnCommitsParametersExtractor.class); + + private final SinceLastTagCommitCollector.Factory sinceLastTagCommitCollectorFactory; + + @Inject + public FireEventOnCommitsParametersExtractor( + SinceLastTagCommitCollector.Factory sinceLastTagCommitCollectorFactory) { + this.sinceLastTagCommitCollectorFactory = sinceLastTagCommitCollectorFactory; + } + + private CommitCollector getCommitCollector(String name) { + switch (name) { + case "since-last-tag": + return sinceLastTagCommitCollectorFactory.create(); + default: + return null; + } + } + + /** + * @return The parameters needed by {@link FireEventOnCommits}. Empty if the parameters could not + * be extracted. + */ + public Optional<FireEventOnCommitsParameters> extract( + ActionRequest actionRequest, Map<String, String> properties) { + String[] parameters = actionRequest.getParameters(); + if (parameters.length != 1) { + log.error( + "Wrong number of received parameters. Received parameters are {}. Only one parameter is expected, the collector name.", + Arrays.toString(parameters)); + return Optional.empty(); + } + + String collectorName = parameters[0]; + if (Strings.isNullOrEmpty(collectorName)) { + log.error("Received collector name is blank"); + return Optional.empty(); + } + + CommitCollector commitCollector = getCommitCollector(collectorName); + if (commitCollector == null) { + log.error("No commit collector found for name {}", collectorName); + return Optional.empty(); + } + + String projectName = properties.get("project"); + return Optional.of(new FireEventOnCommitsParameters(commitCollector, projectName)); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheImpl.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheImpl.java index 72fe43f..4dc46d3 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheImpl.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheImpl.java
@@ -98,7 +98,10 @@ @Override public List<Rule> load(String projectName) throws IOException { - ProjectState project = projectCache.checkedGet(Project.nameKey(projectName)); + ProjectState project = + projectCache + .get(Project.nameKey(projectName)) + .orElseThrow(() -> new IOException("Can't load " + projectName)); List<Rule> projectRules = readRulesFrom(project); if (projectRules.isEmpty()) { for (ProjectState parent : project.parents()) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/RefEventProperties.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/RefEventProperties.java index 30940bb..01b6395 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/RefEventProperties.java +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/RefEventProperties.java
@@ -14,7 +14,6 @@ package com.googlesource.gerrit.plugins.its.base.workflow; -import java.util.Collections; import java.util.Map; import java.util.Set; @@ -31,8 +30,8 @@ */ public RefEventProperties( Map<String, String> projectProperties, Set<Map<String, String>> issuesProperties) { - this.projectProperties = Collections.unmodifiableMap(projectProperties); - this.issuesProperties = Collections.unmodifiableSet(issuesProperties); + this.projectProperties = projectProperties; + this.issuesProperties = issuesProperties; } /** @return Properties of the ref event */
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/commit_collector/CommitCollector.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/commit_collector/CommitCollector.java new file mode 100644 index 0000000..73ea110 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/commit_collector/CommitCollector.java
@@ -0,0 +1,24 @@ +// 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.commit_collector; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** Collects commits based on the event properties provided in input */ +public interface CommitCollector { + List<String> collect(Map<String, String> properties) throws IOException; +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/commit_collector/SinceLastTagCommitCollector.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/commit_collector/SinceLastTagCommitCollector.java new file mode 100644 index 0000000..d8f1ec1 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/commit_collector/SinceLastTagCommitCollector.java
@@ -0,0 +1,97 @@ +// 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.commit_collector; + +import com.google.gerrit.entities.Project; +import com.google.gerrit.server.git.GitRepositoryManager; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import javax.inject.Inject; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevTag; +import org.eclipse.jgit.revwalk.RevWalk; + +/** Collects all commits between the last tag and HEAD */ +public class SinceLastTagCommitCollector implements CommitCollector { + + public interface Factory { + SinceLastTagCommitCollector create(); + } + + private final GitRepositoryManager repoManager; + + @Inject + public SinceLastTagCommitCollector(GitRepositoryManager repoManager) { + this.repoManager = repoManager; + } + + @Override + public List<String> collect(Map<String, String> properties) throws IOException { + String projectName = properties.get("project"); + String revision = properties.get("revision"); + + try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) { + return collect(repo, revision); + } + } + + private List<String> collect(Repository repo, String currentRevision) throws IOException { + try (RevWalk revWalk = new RevWalk(repo)) { + RevCommit currentCommit = revWalk.parseCommit(repo.resolve(currentRevision)); + revWalk.markStart(currentCommit); + List<String> commitIds = new ArrayList<>(); + for (RevCommit commit : revWalk) { + if (!currentCommit.getId().equals(commit.getId()) && isTagged(repo, commit)) { + break; + } + commitIds.add(ObjectId.toString(commit.getId())); + } + return commitIds; + } + } + + /** @return True if {@code commit} is tagged */ + private boolean isTagged(Repository repo, RevCommit commit) throws IOException { + ObjectId commitId = commit.getId(); + try (RevWalk revWalk = new RevWalk(repo)) { + return repo.getRefDatabase().getRefsByPrefix(Constants.R_TAGS).stream() + .map(Ref::getObjectId) + .map( + refObjectId -> { + try { + return revWalk.parseTag(refObjectId); + } catch (IncorrectObjectTypeException e) { + return null; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }) + .filter(Objects::nonNull) + .map(RevTag::getObject) + .map(RevObject::getId) + .anyMatch(commitId::equals); + } + } +}
diff --git a/src/main/resources/Documentation/config-rulebase-common.md b/src/main/resources/Documentation/config-rulebase-common.md index d232e57..50e1023 100644 --- a/src/main/resources/Documentation/config-rulebase-common.md +++ b/src/main/resources/Documentation/config-rulebase-common.md
@@ -574,6 +574,13 @@ `uploaderUsername` : username of the user that uploaded this patch set. +### Common properties for all events + +`source` +: source of the event that triggered the action. Can be `its` or `gerrit`. + `its` sourced events are fired by its actions. e.g. `fire-event-on-commits` action fires `its` sourced events. + `gerrit` sourced events are directly fired by the Gerrit event system. + ## Actions Lines of the form @@ -693,6 +700,26 @@ action = create-version-from-property ref ``` +### Action: fire-event-on-commits + +The `fire-event-on-commits` action start by collecting commits using a collector then fire the event +on each collected commit. + +This is useful when you want to trigger rules on a multiple past commits. + +Available collectors are: +- `since-last-tag`: Collects all commits between the current ref and previous tag + +To avoid to trigger issue actions twice for the same event, you should condition your rule on +the event property `source`. + +Example: + +``` + action = fire-event-on-commits since-last-tag +``` + + ### Action: log-event The `log-event` action appends the event's properties to Gerrit's log.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfigTest.java index 3379908..34068bb 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfigTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfigTest.java
@@ -56,8 +56,8 @@ String enabled, String itsProject, String parentEnabled, String[] branches) { ProjectState projectState = mock(ProjectState.class); - when(projectCache.get(Project.nameKey("testProject"))).thenReturn(projectState); - when(projectCache.get(Project.nameKey("parentProject"))).thenReturn(projectState); + when(projectCache.get(Project.nameKey("testProject"))).thenReturn(Optional.of(projectState)); + when(projectCache.get(Project.nameKey("parentProject"))).thenReturn(Optional.of(projectState)); Iterable<ProjectState> parents; if (parentEnabled == null) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractorTest.java index ac7ea92..d4f0605 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractorTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractorTest.java
@@ -41,6 +41,7 @@ import com.google.inject.Guice; import com.google.inject.Injector; import com.googlesource.gerrit.plugins.its.base.testutil.LoggingMockingTestCase; +import com.googlesource.gerrit.plugins.its.base.workflow.RefEventProperties; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -374,13 +375,30 @@ when(issueExtractor.getIssueIds("testProject", "testRevision")).thenReturn(issueMap); } - Set<Map<String, String>> actual = propertyExtractor.extractFrom(event).getIssuesProperties(); + RefEventProperties refEventProperties = propertyExtractor.extractFrom(event); + + Map<String, String> actualProjectProperties = refEventProperties.getProjectProperties(); + + Map<String, String> expectedProjectProperties = + ImmutableMap.<String, String>builder() + .put("itsName", "ItsTestName") + .put("event", "com.google.gerrit.server.events." + className) + .put("event-type", type) + .put("source", "gerrit") + .putAll(common) + .build(); + + assertEquals( + "Project properties do not match", expectedProjectProperties, actualProjectProperties); + + Set<Map<String, String>> actualIssuesProperties = refEventProperties.getIssuesProperties(); Map<String, String> propertiesIssue4711 = ImmutableMap.<String, String>builder() .put("itsName", "ItsTestName") .put("event", "com.google.gerrit.server.events." + className) .put("event-type", type) + .put("source", "its") .put("association", "body anywhere") .put("issue", "4711") .putAll(common) @@ -390,15 +408,17 @@ .put("itsName", "ItsTestName") .put("event", "com.google.gerrit.server.events." + className) .put("event-type", type) + .put("source", "its") .put("association", "anywhere footer") .put("issue", "42") .putAll(common) .build(); - Set<Map<String, String>> expected = new HashSet<>(); - expected.add(propertiesIssue4711); - expected.add(propertiesIssue42); + Set<Map<String, String>> expectedIssuesProperties = new HashSet<>(); + expectedIssuesProperties.add(propertiesIssue4711); + expectedIssuesProperties.add(propertiesIssue42); - assertEquals("Properties do not match", expected, actual); + assertEquals( + "Issues properties do not match", expectedIssuesProperties, actualIssuesProperties); } @Override
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 5b8c43f..822602b 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
@@ -48,6 +48,7 @@ private LogEvent.Factory logEventFactory; private AddPropertyToField.Factory addPropertyToFieldFactory; private CreateVersionFromProperty.Factory createVersionFromPropertyFactory; + private FireEventOnCommits.Factory fireEventOnCommitsFactory; private CustomAction customAction; private Map<String, String> properties = @@ -212,7 +213,8 @@ CreateVersionFromProperty createVersionFromProperty = mock(CreateVersionFromProperty.class); when(createVersionFromPropertyFactory.create()).thenReturn(createVersionFromProperty); - when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its); + when(itsFacadeFactory.getFacade(Project.nameKey(projectProperties.get("project")))) + .thenReturn(its); ActionExecutor actionExecutor = createActionExecutor(); actionExecutor.executeOnProject(Collections.singleton(actionRequest), projectProperties); @@ -237,6 +239,21 @@ verify(addPropertyToField).execute(its, "4711", actionRequest, properties); } + public void testFireEventOnCommitsDelegation() throws IOException { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getName()).thenReturn("fire-event-on-commits"); + + FireEventOnCommits fireEventOnCommits = mock(FireEventOnCommits.class); + when(fireEventOnCommitsFactory.create()).thenReturn(fireEventOnCommits); + when(itsFacadeFactory.getFacade(Project.nameKey(projectProperties.get("project")))) + .thenReturn(its); + + ActionExecutor actionExecutor = createActionExecutor(); + actionExecutor.executeOnProject(Collections.singleton(actionRequest), projectProperties); + + verify(fireEventOnCommits).execute(its, "itsTestProject", actionRequest, projectProperties); + } + public void testExecuteIssueCustomAction() throws IOException { when(customAction.getType()).thenReturn(ActionType.ISSUE); @@ -304,6 +321,9 @@ createVersionFromPropertyFactory = mock(CreateVersionFromProperty.Factory.class); bind(CreateVersionFromProperty.Factory.class).toInstance(createVersionFromPropertyFactory); + fireEventOnCommitsFactory = mock(FireEventOnCommits.Factory.class); + bind(FireEventOnCommits.Factory.class).toInstance(fireEventOnCommitsFactory); + DynamicMap.mapOf(binder(), CustomAction.class); customAction = mock(CustomAction.class);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParametersExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParametersExtractorTest.java new file mode 100644 index 0000000..c99bf33 --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsParametersExtractorTest.java
@@ -0,0 +1,102 @@ +// 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 static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.gerrit.extensions.config.FactoryModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.googlesource.gerrit.plugins.its.base.workflow.commit_collector.SinceLastTagCommitCollector; +import java.util.Collections; +import java.util.Optional; +import junit.framework.TestCase; + +public class FireEventOnCommitsParametersExtractorTest extends TestCase { + + private static final String SINCE_LAST_TAG_COLLECTOR = "since-last-tag"; + + private SinceLastTagCommitCollector.Factory sinceLastTagCommitCollectorFactory; + private FireEventOnCommitsParametersExtractor extractor; + + @Override + public void setUp() throws Exception { + super.setUp(); + Injector injector = Guice.createInjector(new TestModule()); + extractor = injector.getInstance(FireEventOnCommitsParametersExtractor.class); + } + + private class TestModule extends FactoryModule { + @Override + protected void configure() { + sinceLastTagCommitCollectorFactory = mock(SinceLastTagCommitCollector.Factory.class); + bind(SinceLastTagCommitCollector.Factory.class) + .toInstance(sinceLastTagCommitCollectorFactory); + } + } + + public void testNoParameter() { + testWrongNumberOfReceivedParameters(new String[] {}); + } + + public void testTwoParameters() { + testWrongNumberOfReceivedParameters( + new String[] {SINCE_LAST_TAG_COLLECTOR, SINCE_LAST_TAG_COLLECTOR}); + } + + private void testWrongNumberOfReceivedParameters(String[] parameters) { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getParameters()).thenReturn(parameters); + + Optional<FireEventOnCommitsParameters> extractedParameters = + extractor.extract(actionRequest, Collections.emptyMap()); + assertFalse(extractedParameters.isPresent()); + } + + public void testBlankCollectorName() { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getParameters()).thenReturn(new String[] {""}); + + Optional<FireEventOnCommitsParameters> extractedParameters = + extractor.extract(actionRequest, Collections.emptyMap()); + assertFalse(extractedParameters.isPresent()); + } + + public void testUnknownCollectorName() { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getParameters()).thenReturn(new String[] {"foo"}); + + Optional<FireEventOnCommitsParameters> extractedParameters = + extractor.extract(actionRequest, Collections.emptyMap()); + assertFalse(extractedParameters.isPresent()); + } + + public void testSinceLastTagCollector() { + ActionRequest actionRequest = mock(ActionRequest.class); + when(actionRequest.getParameters()).thenReturn(new String[] {SINCE_LAST_TAG_COLLECTOR}); + + SinceLastTagCommitCollector collector = mock(SinceLastTagCommitCollector.class); + when(sinceLastTagCommitCollectorFactory.create()).thenReturn(collector); + + Optional<FireEventOnCommitsParameters> extractedParameters = + extractor.extract(actionRequest, Collections.singletonMap("project", "testProject")); + if (!extractedParameters.isPresent()) { + fail(); + } + assertEquals(collector, extractedParameters.get().getCommitCollector()); + assertEquals("testProject", extractedParameters.get().getProjectName()); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsTest.java new file mode 100644 index 0000000..e80081d --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/FireEventOnCommitsTest.java
@@ -0,0 +1,115 @@ +// 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 static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.gerrit.extensions.config.FactoryModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.googlesource.gerrit.plugins.its.base.its.ItsFacade; +import com.googlesource.gerrit.plugins.its.base.util.IssueExtractor; +import com.googlesource.gerrit.plugins.its.base.util.PropertyExtractor; +import com.googlesource.gerrit.plugins.its.base.workflow.commit_collector.SinceLastTagCommitCollector; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import junit.framework.TestCase; + +public class FireEventOnCommitsTest extends TestCase { + + private static final String ITS_PROJECT = "test-project"; + private static final String COMMIT = "1234"; + private static final String PROJECT = "testProject"; + + private Injector injector; + private ItsFacade its; + private PropertyExtractor propertyExtractor; + private IssueExtractor issueExtractor; + private RuleBase ruleBase; + private ActionExecutor actionExecutor; + private FireEventOnCommitsParametersExtractor parametersExtractor; + + @Override + public void setUp() throws Exception { + super.setUp(); + injector = Guice.createInjector(new TestModule()); + } + + private class TestModule extends FactoryModule { + @Override + protected void configure() { + its = mock(ItsFacade.class); + bind(ItsFacade.class).toInstance(its); + + propertyExtractor = mock(PropertyExtractor.class); + bind(PropertyExtractor.class).toInstance(propertyExtractor); + + ruleBase = mock(RuleBase.class); + bind(RuleBase.class).toInstance(ruleBase); + + issueExtractor = mock(IssueExtractor.class); + bind(IssueExtractor.class).toInstance(issueExtractor); + + actionExecutor = mock(ActionExecutor.class); + bind(ActionExecutor.class).toInstance(actionExecutor); + + parametersExtractor = mock(FireEventOnCommitsParametersExtractor.class); + bind(FireEventOnCommitsParametersExtractor.class).toInstance(parametersExtractor); + } + } + + public void testHappyPath() throws IOException { + Map<String, String> properties = ImmutableMap.of("project", PROJECT); + + FireEventOnCommitsParameters parameters = mock(FireEventOnCommitsParameters.class); + SinceLastTagCommitCollector collector = mock(SinceLastTagCommitCollector.class); + when(parameters.getCommitCollector()).thenReturn(collector); + when(parameters.getProjectName()).thenReturn(PROJECT); + + ActionRequest actionRequest = mock(ActionRequest.class); + when(parametersExtractor.extract(actionRequest, properties)) + .thenReturn(Optional.of(parameters)); + when(collector.collect(properties)).thenReturn(Collections.singletonList(COMMIT)); + + Map<String, Set<String>> associations = Maps.newHashMap(); + when(issueExtractor.getIssueIds(PROJECT, COMMIT)).thenReturn(associations); + + Set<Map<String, String>> issuesProperties = ImmutableSet.of(properties); + when(propertyExtractor.extractIssuesProperties(properties, associations)) + .thenReturn(issuesProperties); + + ActionRequest subActionRequest = mock(ActionRequest.class); + Collection<ActionRequest> subActionRequests = Collections.singleton(subActionRequest); + when(ruleBase.actionRequestsFor(properties)).thenReturn(subActionRequests); + + FireEventOnCommits fireEventOnCommits = createFireEventOnCommits(); + fireEventOnCommits.execute(its, ITS_PROJECT, actionRequest, properties); + + verify(actionExecutor).executeOnIssue(subActionRequests, properties); + } + + private FireEventOnCommits createFireEventOnCommits() { + return injector.getInstance(FireEventOnCommits.class); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheTest.java index 6b83097..592722c 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheTest.java
@@ -36,6 +36,7 @@ import java.io.IOException; import java.util.Collection; import java.util.List; +import java.util.Optional; import org.eclipse.jgit.lib.Config; public class ItsRulesProjectCacheTest extends LoggingMockingTestCase { @@ -90,7 +91,7 @@ ProjectLevelConfig projectLevelConfigPlugin = mock(ProjectLevelConfig.class); when(projectLevelConfigPlugin.get()).thenReturn(new Config()); when(projectState.getConfig(RuleBaseKind.ITS.fileName)).thenReturn(projectLevelConfigPlugin); - when(projectCache.checkedGet(Project.nameKey(TEST_PROJECT))).thenReturn(projectState); + when(projectCache.get(Project.nameKey(TEST_PROJECT))).thenReturn(Optional.of(projectState)); when(rulesConfigReader.getRulesFromConfig(any(Config.class))) .thenReturn(ImmutableList.of(rule1)) .thenReturn(ImmutableList.of()); @@ -132,7 +133,7 @@ when(parentProjectState.getConfig(RuleBaseKind.ITS.fileName)) .thenReturn(parentProjectConfigPlugin); when(projectState.parents()).thenReturn(FluentIterable.of(parentProjectState)); - when(projectCache.checkedGet(Project.nameKey(TEST_PROJECT))).thenReturn(projectState); + when(projectCache.get(Project.nameKey(TEST_PROJECT))).thenReturn(Optional.of(projectState)); when(rulesConfigReader.getRulesFromConfig(any(Config.class))) .thenReturn(ImmutableList.of())