Merge branch 'stable-3.4'
* stable-3.4:
Decrease size of serialized ParsingQueueTask
TestEventPublisher: performance improvement
Solves: Jira GER-1554
Change-Id: I38c160f94e71c995a2dc19336bbd475785102371
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/Module.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/Module.java
index 9bdc0c4..c5e4c20 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/Module.java
@@ -30,6 +30,7 @@
import com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventMappingConfig;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventParsingConfig;
+import com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter;
import com.googlesource.gerrit.plugins.eventseiffel.config.GraphQlApiConfig;
import com.googlesource.gerrit.plugins.eventseiffel.config.RabbitMqConfig;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.api.EiffelEventPublisher;
@@ -98,6 +99,7 @@
bind(EventParsingConfig.class)
.toProvider(EventParsingConfig.Provider.class)
.in(Scopes.SINGLETON);
+ bind(EventsFilter.class).toProvider(EventsFilter.Provider.class);
bind(EiffelEventParsingExecutor.Scheduled.class).in(Scopes.SINGLETON);
bind(EiffelEventParsingExecutor.class).to(EiffelEventParsingExecutor.Scheduled.class);
bind(EiffelEventParser.class).to(EiffelEventParserImpl.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCacheImpl.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCacheImpl.java
index 5377521..fa7d622 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCacheImpl.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCacheImpl.java
@@ -19,7 +19,6 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.cache.Weigher;
import com.google.gerrit.server.cache.CacheModule;
import com.google.inject.Inject;
import com.google.inject.Module;
@@ -53,7 +52,6 @@
persist(CACHE_NAME, EventKey.class, new TypeLiteral<Optional<UUID>>() {})
.maximumWeight(maxNbrOfEntries)
.loader(EventLoader.class)
- .weigher(CountWeigher.class)
.keySerializer(new EventKeySerializer())
.valueSerializer(new UUIDSerializer());
bind(EiffelEventIdCacheImpl.class).asEagerSingleton();
@@ -155,12 +153,4 @@
return es.getEventId(key);
}
}
-
- static class CountWeigher implements Weigher<EventKey, Optional<UUID>> {
-
- @Override
- public int weigh(EventKey key, Optional<UUID> value) {
- return 1;
- }
- }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventListenersConfig.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventListenersConfig.java
index 32f51c5..cc89f39 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventListenersConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventListenersConfig.java
@@ -16,15 +16,11 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.entities.AccessSection;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.inject.Inject;
-import java.util.Arrays;
-import java.util.function.Function;
-import java.util.regex.Pattern;
import org.eclipse.jgit.lib.Config;
public class EventListenersConfig {
@@ -32,31 +28,10 @@
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
static final String EVENT_LISTENERS = "EventListeners";
static final String ENABLED = "enabled";
- static final String BLOCKED_REFS = "blockedRef";
- static final String BLOCKED_PROJECTS = "blockedProject";
-
- @VisibleForTesting
- static boolean filterMatches(String filter, String repoName) {
- if (filter.startsWith(AccessSection.REGEX_PREFIX)) {
- return Pattern.matches(filter, repoName);
- }
- if (filter.endsWith("*")) {
- return repoName.startsWith(filter.substring(0, filter.length() - 1));
- }
- return repoName.equals(filter);
- }
-
- @VisibleForTesting
- public static Function<String, Boolean> toCombinedMatcher(String... filters) {
- return repoName -> Arrays.stream(filters).anyMatch(f -> filterMatches(f, repoName));
- }
@VisibleForTesting
static EventListenersConfig fromConfig(Config cfg) {
- return new EventListenersConfig(
- cfg.getBoolean(EVENT_LISTENERS, ENABLED, true),
- toCombinedMatcher(cfg.getStringList(EVENT_LISTENERS, null, BLOCKED_PROJECTS)),
- toCombinedMatcher(cfg.getStringList(EVENT_LISTENERS, null, BLOCKED_REFS)));
+ return new EventListenersConfig(cfg.getBoolean(EVENT_LISTENERS, ENABLED, true));
}
private final PluginConfigFactory configFactory;
@@ -81,34 +56,19 @@
} catch (NoSuchProjectException e) {
logger.atSevere().withCause(e).log(
"Unable to read project.config, using default EventListenersConfig");
- return new EventListenersConfig(true, toCombinedMatcher(""), toCombinedMatcher(""));
+ return new EventListenersConfig(true);
}
}
}
private final boolean enabled;
- private final Function<String, Boolean> blockedRefMatcher;
- private final Function<String, Boolean> blockedProjectMatcher;
@VisibleForTesting
- public EventListenersConfig(
- boolean enabled,
- Function<String, Boolean> blockedProjectMatcher,
- Function<String, Boolean> blockedRefMatcher) {
+ public EventListenersConfig(boolean enabled) {
this.enabled = enabled;
- this.blockedProjectMatcher = blockedProjectMatcher;
- this.blockedRefMatcher = blockedRefMatcher;
}
public boolean isEnabled() {
return this.enabled;
}
-
- public boolean refIsBlocked(String ref) {
- return blockedRefMatcher.apply(ref);
- }
-
- public boolean projectIsBlocked(String repoName) {
- return blockedProjectMatcher.apply(repoName);
- }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventsFilter.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventsFilter.java
new file mode 100644
index 0000000..38f3acc
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventsFilter.java
@@ -0,0 +1,114 @@
+// Copyright (C) 2022 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.eventseiffel.config;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.AccessSection;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.project.NoSuchProjectException;
+import com.google.inject.Inject;
+import java.util.Arrays;
+import java.util.function.Function;
+import java.util.regex.Pattern;
+import org.eclipse.jgit.lib.Config;
+
+public class EventsFilter {
+
+ public static class Provider implements com.google.inject.Provider<EventsFilter> {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ static final String EVENTS_FILTER = "EventsFilter";
+ static final String BLOCKED_REFS = "blockedRef";
+ static final String BLOCKED_PROJECTS = "blockedProject";
+ static final String BLOCK_LIGHTWEIGHT_TAGS = "blockLightWeightTags";
+
+ @VisibleForTesting
+ static boolean filterMatches(String filter, String repoName) {
+ if (filter.startsWith(AccessSection.REGEX_PREFIX)) {
+ return Pattern.matches(filter, repoName);
+ }
+ if (filter.endsWith("*")) {
+ return repoName.startsWith(filter.substring(0, filter.length() - 1));
+ }
+ return repoName.equals(filter);
+ }
+
+ @VisibleForTesting
+ public static Function<String, Boolean> toCombinedMatcher(String... filters) {
+ return repoName -> Arrays.stream(filters).anyMatch(f -> filterMatches(f, repoName));
+ }
+
+ @VisibleForTesting
+ static EventsFilter fromConfig(Config cfg) {
+ return new EventsFilter(
+ toCombinedMatcher(cfg.getStringList(EVENTS_FILTER, null, BLOCKED_PROJECTS)),
+ toCombinedMatcher(cfg.getStringList(EVENTS_FILTER, null, BLOCKED_REFS)),
+ cfg.getBoolean(EVENTS_FILTER, BLOCK_LIGHTWEIGHT_TAGS, false));
+ }
+
+ private final PluginConfigFactory configFactory;
+ private final String pluginName;
+ private final AllProjectsName allProjects;
+
+ @Inject
+ public Provider(
+ PluginConfigFactory cfgFactory,
+ @PluginName String pluginName,
+ AllProjectsName allProjects) {
+ this.configFactory = cfgFactory;
+ this.pluginName = pluginName;
+ this.allProjects = allProjects;
+ }
+
+ @Override
+ public EventsFilter get() {
+ try {
+ Config cfg = configFactory.getProjectPluginConfig(allProjects, pluginName);
+ return fromConfig(cfg);
+ } catch (NoSuchProjectException e) {
+ logger.atSevere().withCause(e).log(
+ "Unable to read project.config, using default EventsFilter");
+ return new EventsFilter(toCombinedMatcher(""), toCombinedMatcher(""), false);
+ }
+ }
+ }
+
+ private final Function<String, Boolean> blockedRefMatcher;
+ private final Function<String, Boolean> blockedProjectMatcher;
+ private final boolean blockLightWeightTags;
+
+ @VisibleForTesting
+ public EventsFilter(
+ Function<String, Boolean> blockedProjectMatcher,
+ Function<String, Boolean> blockedRefMatcher,
+ boolean blockLightWeightTags) {
+ this.blockedProjectMatcher = blockedProjectMatcher;
+ this.blockedRefMatcher = blockedRefMatcher;
+ this.blockLightWeightTags = blockLightWeightTags;
+ }
+
+ public boolean refIsBlocked(String ref) {
+ return blockedRefMatcher.apply(ref);
+ }
+
+ public boolean projectIsBlocked(String repoName) {
+ return blockedProjectMatcher.apply(repoName);
+ }
+
+ public boolean blockLightWeightTags() {
+ return blockLightWeightTags;
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGraphQlClient.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGraphQlClient.java
index c3c9201..ff8bf2b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGraphQlClient.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGraphQlClient.java
@@ -14,6 +14,11 @@
package com.googlesource.gerrit.plugins.eventseiffel.eiffel.api;
+import com.github.rholder.retry.RetryException;
+import com.github.rholder.retry.Retryer;
+import com.github.rholder.retry.RetryerBuilder;
+import com.github.rholder.retry.StopStrategies;
+import com.github.rholder.retry.WaitStrategies;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.flogger.FluentLogger;
@@ -37,6 +42,8 @@
import java.util.List;
import java.util.Optional;
import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class EiffelGraphQlClient implements EventStorage {
@@ -131,8 +138,14 @@
private QueryResult query(String query) throws EventStorageException {
HttpResponse<String> response;
try {
- response = post(query);
- } catch (IOException | InterruptedException e) {
+ Retryer<HttpResponse<String>> retryer =
+ RetryerBuilder.<HttpResponse<String>>newBuilder()
+ .retryIfException()
+ .withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
+ .withStopStrategy(StopStrategies.stopAfterAttempt(2))
+ .build();
+ response = retryer.call(() -> post(query));
+ } catch (RetryException | ExecutionException e) {
throw new EventStorageException(e, "Query \"%s\" failed.", query);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/PatchsetCreatedListener.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/PatchsetCreatedListener.java
index 4d07ca8..048f701 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/PatchsetCreatedListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/PatchsetCreatedListener.java
@@ -18,30 +18,35 @@
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig;
+import com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParsingQueue;
public class PatchsetCreatedListener implements RevisionCreatedListener {
private final EiffelEventParsingQueue queue;
private final Provider<EventListenersConfig> configProvider;
+ private final Provider<EventsFilter> eventsFilter;
@Inject
public PatchsetCreatedListener(
- EiffelEventParsingQueue queue, Provider<EventListenersConfig> config) {
+ EiffelEventParsingQueue queue,
+ Provider<EventListenersConfig> configProvider,
+ Provider<EventsFilter> eventsFilter) {
this.queue = queue;
- this.configProvider = config;
+ this.configProvider = configProvider;
+ this.eventsFilter = eventsFilter;
}
@Override
public void onRevisionCreated(RevisionCreatedListener.Event event) {
- EventListenersConfig config = configProvider.get();
- if (!config.isEnabled()) {
+ if (!configProvider.get().isEnabled()) {
return;
}
/* 'branch' is not the exact reference in this case.
* Filtering for startsWith("refs/") to filter out refs/meta/config.*/
if (!event.getChange().branch.startsWith(RefNames.REFS)) {
- if (config.refIsBlocked(RefNames.REFS_HEADS + event.getChange().branch)
- || config.projectIsBlocked(event.getChange().project)) {
+ EventsFilter filter = eventsFilter.get();
+ if (filter.refIsBlocked(RefNames.REFS_HEADS + event.getChange().branch)
+ || filter.projectIsBlocked(event.getChange().project)) {
return;
}
queue.scheduleSccCreation(event);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/RefUpdateListener.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/RefUpdateListener.java
index 98ca829..3a04f53 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/RefUpdateListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/RefUpdateListener.java
@@ -18,18 +18,23 @@
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig;
+import com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParsingQueue;
public class RefUpdateListener implements GitReferenceUpdatedListener {
private final EiffelEventParsingQueue queue;
private final Provider<EventListenersConfig> configProvider;
+ private final Provider<EventsFilter> eventsFilter;
@Inject
public RefUpdateListener(
- EiffelEventParsingQueue queue, Provider<EventListenersConfig> configProvider) {
+ EiffelEventParsingQueue queue,
+ Provider<EventListenersConfig> configProvider,
+ Provider<EventsFilter> eventsFilter) {
this.queue = queue;
this.configProvider = configProvider;
+ this.eventsFilter = eventsFilter;
}
@Override
@@ -39,8 +44,10 @@
return;
}
- if (config.refIsBlocked(event.getRefName())
- || config.projectIsBlocked(event.getProjectName())) {
+ EventsFilter filter = eventsFilter.get();
+
+ if (filter.refIsBlocked(event.getRefName())
+ || filter.projectIsBlocked(event.getProjectName())) {
return;
}
/* The reference was not deleted. */
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserImpl.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserImpl.java
index 5489a74..b2320b5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserImpl.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserImpl.java
@@ -30,8 +30,10 @@
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
+import com.google.inject.Provider;
import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventHub;
import com.googlesource.gerrit.plugins.eventseiffel.cache.EiffelEventIdLookupException;
+import com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.CompositionDefinedEventKey;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey;
@@ -55,6 +57,8 @@
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.RevWalkUtils;
/** Creates and pushes missing Eiffel events to the Eiffel event queue. */
public class EiffelEventParserImpl implements EiffelEventParser {
@@ -66,17 +70,20 @@
private final GitRepositoryManager repoManager;
private final UnprocessedCommitsWalker.Factory walkerFactory;
private final EiffelEventMapper mapper;
+ private final Provider<EventsFilter> eventsFilter;
@Inject
public EiffelEventParserImpl(
EiffelEventHub eventQueue,
GitRepositoryManager repoManager,
EiffelEventMapper mapper,
- UnprocessedCommitsWalker.Factory walkerFactory) {
+ UnprocessedCommitsWalker.Factory walkerFactory,
+ Provider<EventsFilter> eventsFilter) {
this.eventHub = eventQueue;
this.repoManager = repoManager;
this.walkerFactory = walkerFactory;
this.mapper = mapper;
+ this.eventsFilter = eventsFilter;
}
/* (non-Javadoc)
@@ -203,15 +210,6 @@
throw new EiffelEventIdLookupException(
"Unable to find SCC event id: %s", create.key.copy(SCC));
}
- List<UUID> scsParentEventIds = Lists.newArrayList();
- for (RevCommit parent : create.commit.getParents()) {
- Optional<UUID> parentUuid = eventHub.getExistingId(create.key.copy(parent.getName()));
- if (parentUuid.isPresent()) {
- scsParentEventIds.add(parentUuid.get());
- } else {
- exceptionForMissingParent(create, parent);
- }
- }
pushToHub(
mapper.toScs(
create.commit,
@@ -219,7 +217,7 @@
create.key.branch(),
create.submitter,
create.submittedAt,
- scsParentEventIds,
+ getParentUuids(create.key, create.commit),
sccId.get()));
}
}
@@ -268,67 +266,116 @@
}
private void createAndScheduleCd(
- String repoName, String tagName, Long creationTime, boolean force)
+ String projectName, String tagName, Long creationTime, boolean force)
throws EventParsingException {
- SourceChangeEventKey scs = null;
Optional<UUID> scsId = Optional.empty();
+ List<Ref> refs = null;
try {
- String commitId = peelTag(repoName, tagName);
- scs = SourceChangeEventKey.scsKey(repoName, RefNames.REFS_HEADS + "master", commitId);
+ EventsFilter filter = eventsFilter.get();
+ ObjectId objectId = peelTag(projectName, tagName, filter.blockLightWeightTags());
+ if (objectId == null) {
+ return;
+ }
+ String commitId = objectId.getName();
+
+ /* Check if an event for commit~master has been created. */
+ SourceChangeEventKey scs =
+ SourceChangeEventKey.scsKey(projectName, RefNames.REFS_HEADS + "master", commitId);
scsId = eventHub.getExistingId(scs);
if (scsId.isEmpty()) {
+ /* No event created for commit~master. Check if event is created for any
+ of the other branches. */
Retryer<Optional<UUID>> retryer =
RetryerBuilder.<Optional<UUID>>newBuilder()
.retryIfResult(Optional::isEmpty)
.withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
.withStopStrategy(StopStrategies.stopAfterAttempt(2))
.build();
+ try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
+ refs =
+ repo.getRefDatabase().getRefsByPrefix(RefNames.REFS_HEADS).stream()
+ .collect(Collectors.toList());
+ } catch (IOException e) {
+ throw new EventParsingException(
+ e, "Unable to get branches for: %s:%s", projectName, tagName);
+ }
try {
- scsId = retryer.call(() -> findSourceChangeEventKey(repoName, commitId));
+ List<String> branches =
+ refs.stream()
+ .map(Ref::getName)
+ .filter(branch -> !branch.equals(RefNames.REFS_HEADS + "master"))
+ .collect(Collectors.toList());
+ scsId = retryer.call(() -> findSourceChangeEventKey(projectName, commitId, branches));
} catch (RetryException | ExecutionException e) {
- throw new EventParsingException(e, "Failed to find SCS for %s in %s", commitId, repoName);
+ logger.atWarning().withCause(e).log(
+ "Failed to find SCS for %s in %s when trying to create CD for tag %s",
+ commitId, projectName, tagName);
}
}
+
if (scsId.isEmpty()) {
- throw new EventParsingException("Could not find SCS for: %s in %s", commitId, repoName);
+ /* No event has been created for the commit. Find any non-blocked branch that
+ commit is merged into and create SCS events for that branch. */
+ List<Ref> branches;
+ try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
+ RevWalk rw = new RevWalk(repo);
+ refs =
+ refs.stream()
+ .filter(ref -> !filter.refIsBlocked(ref.getName()))
+ .collect(Collectors.toList());
+ branches = RevWalkUtils.findBranchesReachableFrom(rw.parseCommit(objectId), rw, refs);
+ } catch (IOException e) {
+ throw new EventParsingException(
+ e, "Unable to get reachable branches for: %s:%s", projectName, tagName);
+ }
+ if (branches.isEmpty()) {
+ throw new EventParsingException(
+ "Could not find any unblocked branch for SCS with: %s in %s so CD could not be created for tag %s",
+ commitId, projectName, tagName);
+ }
+ String branch = branches.get(0).getName();
+ scs = SourceChangeEventKey.scsKey(projectName, branch, commitId);
+ createAndScheduleMissingScss(scs, null, null, null);
+ scsId = eventHub.getExistingId(scs);
}
- pushToHub(mapper.toCd(repoName, tagName, creationTime, scsId.get()), force);
+
+ if (scsId.isEmpty()) {
+ throw new EventParsingException(
+ "Could not find or create SCS for %s in %s so CD could not be created for tag %s",
+ commitId, projectName, tagName);
+ }
+ pushToHub(mapper.toCd(projectName, tagName, creationTime, scsId.get()), force);
} catch (EiffelEventIdLookupException | InterruptedException e) {
throw new EventParsingException(
e,
"Event creation failed for: %s",
- CompositionDefinedEventKey.create(mapper.tagCompositionName(repoName), tagName));
+ CompositionDefinedEventKey.create(mapper.tagCompositionName(projectName), tagName));
}
}
- private String peelTag(String repoName, String tagName) throws EventParsingException {
- try (Repository repo = repoManager.openRepository(Project.nameKey(repoName))) {
+ private ObjectId peelTag(String projectName, String tagName, boolean blockLightWeightTags)
+ throws EventParsingException {
+ try (Repository repo = repoManager.openRepository(Project.nameKey(projectName))) {
Ref tagRef = repo.getRefDatabase().exactRef(Constants.R_TAGS + tagName);
if (tagRef != null) {
ObjectId peeled = repo.getRefDatabase().peel(tagRef).getPeeledObjectId();
- return peeled != null ? peeled.getName() : tagRef.getObjectId().getName();
+ if (peeled != null) return peeled;
+ if (!blockLightWeightTags) return tagRef.getObjectId();
+ logger.atInfo().log("Creation of CD is blocked for lightweight tags");
+ return null;
}
- throw new EventParsingException("Cannot find tag: %s:%s", repoName, tagName);
+ throw new EventParsingException("Cannot find tag: %s:%s", projectName, tagName);
} catch (IOException e) {
- throw new EventParsingException(e, "Unable to peel tag: %s:%s", repoName, tagName);
+ throw new EventParsingException(e, "Unable to peel tag: %s:%s", projectName, tagName);
}
}
- private Optional<UUID> findSourceChangeEventKey(String repoName, String commitId)
+ private Optional<UUID> findSourceChangeEventKey(
+ String projectName, String commitId, List<String> branches)
throws EiffelEventIdLookupException {
- List<String> branches;
- try (Repository repo = repoManager.openRepository(Project.nameKey(repoName))) {
- branches =
- repo.getRefDatabase().getRefsByPrefix(RefNames.REFS_HEADS).stream()
- .map(Ref::getName)
- .collect(Collectors.toList());
- } catch (IOException ioe) {
- logger.atSevere().withCause(ioe).log("Unable to find branches of %s.", repoName);
- return Optional.empty();
- }
- return eventHub.getScsForCommit(repoName, commitId, branches);
+ return eventHub.getScsForCommit(projectName, commitId, branches);
}
private void pushToHub(EiffelEvent toPush) throws InterruptedException {
@@ -385,18 +432,10 @@
while (commitFinder.hasNext()) {
EventCreate job = commitFinder.next();
logger.atFine().log("Processing event-creation for: %s", job.key);
- List<UUID> parentIds = Lists.newArrayList();
- for (RevCommit parent : job.commit.getParents()) {
- SourceChangeEventKey parentKey = scc.copy(parent.getName());
- Optional<UUID> parentId = eventHub.getExistingId(parentKey);
- if (parentId.isPresent()) {
- parentIds.add(parentId.get());
- } else {
- exceptionForMissingParent(job, parent);
- }
- }
try {
- pushToHub(mapper.toScc(job.commit, job.key.repo(), job.key.branch(), parentIds));
+ pushToHub(
+ mapper.toScc(
+ job.commit, job.key.repo(), job.key.branch(), getParentUuids(job.key, job.commit)));
} catch (InterruptedException e) {
logger.atSevere().log("Interrupted while pushing %s to EventHub.", job.key);
throw e;
@@ -418,11 +457,26 @@
}
}
- private void exceptionForMissingParent(EventCreate create, RevCommit parent)
+ private List<UUID> getParentUuids(SourceChangeEventKey key, RevCommit commit)
+ throws NoSuchEntityException, EiffelEventIdLookupException {
+ List<UUID> parentIds = Lists.newArrayList();
+ for (RevCommit parent : commit.getParents()) {
+ SourceChangeEventKey parentKey = key.copy(parent.getName());
+ Optional<UUID> parentId = eventHub.getExistingId(parentKey);
+ if (parentId.isPresent()) {
+ parentIds.add(parentId.get());
+ } else {
+ exceptionForMissingParent(key, parent);
+ }
+ }
+ return parentIds;
+ }
+
+ private void exceptionForMissingParent(SourceChangeEventKey key, RevCommit parent)
throws NoSuchEntityException {
throw new NoSuchEntityException(
String.format(
"Unable to lookup parent (%s) event UUID for %s even though it should exist.",
- parent.abbreviate(7).name(), create.key));
+ parent.abbreviate(7).name(), key));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/UnprocessedCommitsWalker.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/UnprocessedCommitsWalker.java
index fb46d82..1ddd0e2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/UnprocessedCommitsWalker.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/UnprocessedCommitsWalker.java
@@ -90,14 +90,8 @@
UnprocessedCommitsWalker(
SourceChangeEventKey eventKey, EiffelEventHub eventHub, GitRepositoryManager repoManager)
throws RepositoryNotFoundException, IOException, EiffelEventIdLookupException {
- this.eventKey = eventKey;
- this.eventHub = eventHub;
- this.repo = repoManager.openRepository(Project.nameKey(eventKey.repo()));
- this.rw = new RevWalk(repo);
- this.toClose.add(repo);
- this.toClose.add(rw);
- rw.setRetainBody(false);
- this.hasEvents = hasEvents();
+ this(eventKey, eventHub, repoManager.openRepository(Project.nameKey(eventKey.repo())));
+ this.toClose.add(this.repo);
}
UnprocessedCommitsWalker(SourceChangeEventKey eventKey, EiffelEventHub eventHub, Repository repo)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/EventCreationResponse.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/EventCreationResponse.java
index 8f43ba9..8303940 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/EventCreationResponse.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/EventCreationResponse.java
@@ -43,7 +43,7 @@
}
static EventCreationResponse artc(TagResource res) {
- return new EventCreationResponse(res, null, ARTC, CD);
+ return new EventCreationResponse(res, null, ARTC, CD, SCS, SCC);
}
private final EventCreationScheduled scheduled;
diff --git a/src/main/resources/Documentation/config-project-level.md b/src/main/resources/Documentation/config-project-level.md
index 844a965..ef8192c 100644
--- a/src/main/resources/Documentation/config-project-level.md
+++ b/src/main/resources/Documentation/config-project-level.md
@@ -11,6 +11,7 @@
blockedRef = ^refs/heads/user/.*
blockedProject = user/projects/*
blockedProject = top/secret/project
+ blockLightWeightTags = True.
```
## Section "EventListeners" ##
@@ -30,3 +31,7 @@
blockedProject
: Pattern(s) that blocks event creation for all matching projects.
Supported: REGEX - if starts with "^", WILDCARD - if ends with "*", EXACT - in other cases.
+
+blockLightWeightTags
+: Decides whether ArtC and CD events should be created for lightweight tags.
+ (Default: _False_).
diff --git a/src/main/resources/Documentation/rest-api-events-eiffel-artc-post.md b/src/main/resources/Documentation/rest-api-events-eiffel-artc-post.md
new file mode 100644
index 0000000..67189f1
--- /dev/null
+++ b/src/main/resources/Documentation/rest-api-events-eiffel-artc-post.md
@@ -0,0 +1,70 @@
+POST createArtcs
+==============================
+
+```
+POST /projects/{project-name}/tags/{tag-name}/@PLUGIN@~createArtcs
+```
+
+DESCRIPTION
+-----------
+Creates missing
+[ArtifactCreatedEvent(ARTC)](https://github.com/eiffel-community/eiffel/blob/edition-paris/eiffel-vocabulary/EiffelArtifactCreatedEvent.md)
+,
+[CompositionDefinedEvent(CD)](https://github.com/eiffel-community/eiffel/blob/edition-paris/eiffel-vocabulary/EiffelCompositionDefinedEvent.md)
+,
+[SourceChangeSubmitted(SCS)](https://github.com/eiffel-community/eiffel/blob/edition-paris/eiffel-vocabulary/EiffelSourceChangeSubmittedEvent.md)
+and
+[SourceChangeCreated(SCC)](https://github.com/eiffel-community/eiffel/blob/edition-paris/eiffel-vocabulary/EiffelSourceChangeCreatedEvent.md)
+events for commit pointed by {tag-name}.
+
+ACCESS
+------
+[Administrate Server](../../../Documentation/access-control.html#capability_administrateServer)
+capability is required.
+
+EXAMPLES
+--------
+
+#### Create missing ARTC events for the tag stable-3.5 of project my/project: ####
+
+```
+ curl -X POST --user janeadmin:secret \
+ -H "content-type:application/json" \
+ http://host:port/a/projects/my%2Fproject/tags/stable-3.5/@PLUGIN@~createArtcs
+```
+
+__Response:__
+
+```
+ )]}'
+ {
+ "types": [
+ "EiffelArtifactCreatedEvent",
+ "EiffelCompositionDefinedEvent",
+ "EiffelSourceChangeCreatedEvent",
+ "EiffelSourceChangeSubmittedEvent",
+ ],
+ "repo_name": "my/project",
+ "ref": "refs/tags/stable-3.5",
+ "status": "Event creation scheduled",
+ }
+```
+
+### Response object ###
+types
+: The types of events that may be created.
+
+repo_name
+: Name of the repository.
+
+ref
+: The ref of the tag from which we will create an ARTC event.
+
+SEE ALSO
+--------
+* [Plugin Development](../../../Documentation/dev-plugins.html)
+* [REST API Protocol Details](../../../Documentation/rest-api.html#_protocol_details)
+
+GERRIT
+------
+Part of [Gerrit Code Review](../../../Documentation/index.html)
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTest.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTest.java
index c847bb0..0433b7a 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTest.java
@@ -15,6 +15,7 @@
package com.googlesource.gerrit.plugins.eventseiffel;
import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter.Provider.toCombinedMatcher;
import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType.SCC;
import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType.SCS;
@@ -24,9 +25,11 @@
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.projects.TagInput;
import com.google.inject.Provider;
+import com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.api.EventStorageException;
+import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkInfo;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkType;
import com.googlesource.gerrit.plugins.eventseiffel.mapping.EiffelEventFactory;
@@ -115,6 +118,22 @@
result.getCommit().getName());
}
+ protected void setScsHandled() throws Exception {
+ markAsHandled(eventForHead(EiffelEventType.SCS), getHead(repo(), "HEAD"));
+ }
+
+ protected SourceChangeEventKey eventForHead(EiffelEventType type) throws Exception {
+ return SourceChangeEventKey.create(project.get(), getHead(), getHeadRevision(), type);
+ }
+
+ protected String getHead() throws Exception {
+ return gApi.projects().name(project.get()).head();
+ }
+
+ protected String getHeadRevision() throws Exception {
+ return getHead(repo(), "HEAD").getName();
+ }
+
protected UUID markAsHandled(EventKey key) throws EventStorageException {
Optional<UUID> eventId = TestEventStorage.INSTANCE.getEventId(key);
if (eventId.isPresent()) {
@@ -184,6 +203,39 @@
return gApi.projects().name(project.get()).tag(input.ref).create(input).get().ref;
}
+ public static class TestEventsFilterProvider implements Provider<EventsFilter> {
+ private static String[] refPatterns;
+ private static String[] projectPatterns;
+ private static boolean blockLightweightTags;
+
+ static {
+ reset();
+ }
+
+ public static void reset() {
+ refPatterns = projectPatterns = new String[0];
+ blockLightweightTags = false;
+ }
+
+ public static void setBlockedRefPatterns(String... patterns) {
+ refPatterns = patterns;
+ }
+
+ public static void setBlockedProjectPatterns(String... patterns) {
+ projectPatterns = patterns;
+ }
+
+ public static void blockLightWeightTags() {
+ blockLightweightTags = true;
+ }
+
+ @Override
+ public EventsFilter get() {
+ return new EventsFilter(
+ toCombinedMatcher(projectPatterns), toCombinedMatcher(refPatterns), blockLightweightTags);
+ }
+ }
+
public static class TestEventFactoryProvider implements Provider<EiffelEventFactory> {
@Override
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTestModule.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTestModule.java
index 17b5acd..345753d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTestModule.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTestModule.java
@@ -20,9 +20,11 @@
import com.google.inject.Singleton;
import com.google.inject.internal.UniqueAnnotations;
import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventsTest.TestEventFactoryProvider;
+import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventsTest.TestEventsFilterProvider;
import com.googlesource.gerrit.plugins.eventseiffel.cache.EiffelEventIdCacheImpl;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventIdCacheConfig;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventMappingConfig;
+import com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.api.EventStorage;
import com.googlesource.gerrit.plugins.eventseiffel.mapping.EiffelEventFactory;
import com.googlesource.gerrit.plugins.eventseiffel.parsing.EiffelEventParser;
@@ -44,6 +46,8 @@
bind(EiffelEventParsingExecutor.class).to(EiffelEventParsingExecutor.Direct.class);
bind(TestEventPublisher.class).in(Scopes.SINGLETON);
bind(EiffelEventHub.Consumer.class).to(TestEventPublisher.class);
+
+ bind(EventsFilter.class).toProvider(TestEventsFilterProvider.class);
bind(EiffelEventParser.class).to(EiffelEventParserImpl.class);
bind(EiffelEventParsingQueue.class);
bind(EiffelEventFactory.class).toProvider(TestEventFactoryProvider.class);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventListenersConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventsFilterTest.java
similarity index 66%
rename from src/test/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventListenersConfigTest.java
rename to src/test/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventsFilterTest.java
index ab2ca17..268cc2c 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventListenersConfigTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/config/EventsFilterTest.java
@@ -14,9 +14,9 @@
package com.googlesource.gerrit.plugins.eventseiffel.config;
-import static com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig.Provider.filterMatches;
-import static com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig.Provider.fromConfig;
-import static com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig.Provider.toCombinedMatcher;
+import static com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter.Provider.filterMatches;
+import static com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter.Provider.fromConfig;
+import static com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter.Provider.toCombinedMatcher;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -24,51 +24,51 @@
import org.eclipse.jgit.lib.Config;
import org.junit.Test;
-public class EventListenersConfigTest {
+public class EventsFilterTest {
@Test
public void regexBlockRefPattern() throws Exception {
- EventListenersConfig cfg = refsPatterns("^refs/.*/blocked");
- assertTrue(cfg.refIsBlocked("refs/that/are/blocked"));
- assertFalse(cfg.refIsBlocked("refs/allowed"));
+ EventsFilter filter = refsPatterns("^refs/.*/blocked");
+ assertTrue(filter.refIsBlocked("refs/that/are/blocked"));
+ assertFalse(filter.refIsBlocked("refs/allowed"));
- cfg = refsPatterns("^refs/(heads|tags)");
- assertTrue(cfg.refIsBlocked("refs/heads"));
- assertTrue(cfg.refIsBlocked("refs/tags"));
- assertFalse(cfg.refIsBlocked("refs/meta"));
+ filter = refsPatterns("^refs/(heads|tags)");
+ assertTrue(filter.refIsBlocked("refs/heads"));
+ assertTrue(filter.refIsBlocked("refs/tags"));
+ assertFalse(filter.refIsBlocked("refs/meta"));
}
@Test
public void wildcardBlockRefPattern() throws Exception {
- EventListenersConfig cfg = refsPatterns("");
- assertFalse(cfg.refIsBlocked("refs/blocked/always"));
+ EventsFilter filter = refsPatterns("");
+ assertFalse(filter.refIsBlocked("refs/blocked/always"));
- cfg = refsPatterns("refs/blocked/*");
- assertTrue(cfg.refIsBlocked("refs/blocked/always"));
- assertFalse(cfg.refIsBlocked("refs/allowed/always"));
+ filter = refsPatterns("refs/blocked/*");
+ assertTrue(filter.refIsBlocked("refs/blocked/always"));
+ assertFalse(filter.refIsBlocked("refs/allowed/always"));
}
@Test
public void exactBlockRefPattern() throws Exception {
- EventListenersConfig cfg = refsPatterns("");
- assertFalse(cfg.refIsBlocked("refs/blocked/exact"));
+ EventsFilter filter = refsPatterns("");
+ assertFalse(filter.refIsBlocked("refs/blocked/exact"));
- cfg = refsPatterns("refs/blocked/exact");
- assertTrue(cfg.refIsBlocked("refs/blocked/exact"));
- assertFalse(cfg.refIsBlocked("refs/blocked/exact2"));
+ filter = refsPatterns("refs/blocked/exact");
+ assertTrue(filter.refIsBlocked("refs/blocked/exact"));
+ assertFalse(filter.refIsBlocked("refs/blocked/exact2"));
}
@Test
public void combinedBlockRefPattern() throws Exception {
- EventListenersConfig cfg = refsPatterns("");
- assertFalse(cfg.refIsBlocked("refs/certainly/blocked"));
- assertFalse(cfg.refIsBlocked("refs/blocked/always"));
- assertFalse(cfg.refIsBlocked("refs/not/allowed/at/all"));
+ EventsFilter filter = refsPatterns("");
+ assertFalse(filter.refIsBlocked("refs/certainly/blocked"));
+ assertFalse(filter.refIsBlocked("refs/blocked/always"));
+ assertFalse(filter.refIsBlocked("refs/not/allowed/at/all"));
- cfg = refsPatterns("refs/blocked/*", "^refs/.*/blocked", "refs/not/allowed/at/all");
- assertTrue(cfg.refIsBlocked("refs/certainly/blocked"));
- assertTrue(cfg.refIsBlocked("refs/blocked/always"));
- assertTrue(cfg.refIsBlocked("refs/not/allowed/at/all"));
+ filter = refsPatterns("refs/blocked/*", "^refs/.*/blocked", "refs/not/allowed/at/all");
+ assertTrue(filter.refIsBlocked("refs/certainly/blocked"));
+ assertTrue(filter.refIsBlocked("refs/blocked/always"));
+ assertTrue(filter.refIsBlocked("refs/not/allowed/at/all"));
}
@Test
@@ -132,26 +132,25 @@
public void configParsedCorrectly() throws Exception {
Config cfg = new Config();
cfg.fromText(
- "[EventListeners]\n"
+ "[EventsFilter]\n"
+ "blockedRef = refs/heads/blocked\n"
+ "blockedRef = refs/heads/also/blocked\n"
+ "blockedProject = blocked/project\n"
+ "blockedProject = blocked/projects/*\n"
+ "enabled = False\n");
- EventListenersConfig fromText = fromConfig(cfg);
+ EventsFilter fromText = fromConfig(cfg);
assertTrue(fromText.refIsBlocked("refs/heads/blocked"));
assertTrue(fromText.refIsBlocked("refs/heads/also/blocked"));
assertTrue(fromText.projectIsBlocked("blocked/project"));
assertTrue(fromText.projectIsBlocked("blocked/projects/something"));
- assertFalse(fromText.isEnabled());
}
- private EventListenersConfig refsPatterns(String... patterns) {
- return new EventListenersConfig(true, toCombinedMatcher(), toCombinedMatcher(patterns));
+ private EventsFilter refsPatterns(String... patterns) {
+ return new EventsFilter(toCombinedMatcher(), toCombinedMatcher(patterns), false);
}
- private EventListenersConfig projectsPatterns(String... patterns) {
- return new EventListenersConfig(true, toCombinedMatcher(patterns), toCombinedMatcher());
+ private EventsFilter projectsPatterns(String... patterns) {
+ return new EventsFilter(toCombinedMatcher(patterns), toCombinedMatcher(), false);
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/GerritEventListenersIT.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/GerritEventListenersIT.java
index 3d93b80..4d0d44d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/GerritEventListenersIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/listeners/GerritEventListenersIT.java
@@ -14,7 +14,6 @@
package com.googlesource.gerrit.plugins.eventseiffel.listeners;
-import static com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig.Provider.toCombinedMatcher;
import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType.SCC;
import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType.SCS;
import static org.junit.Assert.assertEquals;
@@ -37,6 +36,7 @@
import com.googlesource.gerrit.plugins.eventseiffel.TestEventPublisher;
import com.googlesource.gerrit.plugins.eventseiffel.config.EiffelConfig;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig;
+import com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.ArtifactEventKey;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.CompositionDefinedEventKey;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey;
@@ -63,7 +63,8 @@
@Before
public void before() {
publisher = plugin.getSysInjector().getInstance(TestEventPublisher.class);
- TestEventListenerConfigProvider.reset();
+ TestEventsFilterProvider.reset();
+ TestEventListenersConfigProvider.reset();
}
@After
@@ -110,13 +111,13 @@
UUID masterSccEventId = markMasterAsHandled(SCC);
RevCommit previousMaster = getMaster();
- TestEventListenerConfigProvider.disable();
+ TestEventListenersConfigProvider.disable();
PushOneCommit.Result res1 = createChange();
SourceChangeEventKey sccKey1 = toSccKey(res1);
merge(res1);
- TestEventListenerConfigProvider.enable();
+ TestEventListenersConfigProvider.enable();
PushOneCommit.Result res2 = createChange();
SourceChangeEventKey sccKey2 = toSccKey(res2);
@@ -162,7 +163,7 @@
@Test
public void noEventsCreatedWhenDisabled() throws Exception {
- TestEventListenerConfigProvider.disable();
+ TestEventListenersConfigProvider.disable();
PushOneCommit.Result res = createChange();
publisher.assertNotPublished(
toSccKey(res), "Patch-set created shouldn't result in event when disabled");
@@ -173,7 +174,7 @@
@Test
public void noEventsCreatedWhenRefIsBlocked() throws Exception {
- TestEventListenerConfigProvider.setBlockedRefPatterns("refs/heads/master");
+ TestEventsFilterProvider.setBlockedRefPatterns("refs/heads/master");
PushOneCommit.Result res = createChange();
publisher.assertNotPublished(
toSccKey(res), "Patch-set created shouldn't result in event when target ref is blocked");
@@ -184,7 +185,7 @@
@Test
public void noEventsCreatedWhenProjectIsBlocked() throws Exception {
- TestEventListenerConfigProvider.setBlockedProjectPatterns(project.get());
+ TestEventsFilterProvider.setBlockedProjectPatterns(project.get());
PushOneCommit.Result res = createChange();
publisher.assertNotPublished(
toSccKey(res), "Patch-set created shouldn't result in event when project is blocked");
@@ -195,8 +196,16 @@
@Test
public void lightweightTagCreatedResultsInEvent() throws Exception {
- UUID parentEventId = markMasterAsHandled(SCS);
- String tagName = createTagRef(false).substring(RefNames.REFS_TAGS.length());
+ tagCreatedResultsInEvent(false);
+ }
+
+ @Test
+ public void annotatedTagCreatedResultsInEvent() throws Exception {
+ tagCreatedResultsInEvent(true);
+ }
+
+ private void tagCreatedResultsInEvent(boolean annotated) throws Exception {
+ String tagName = createTagRef(annotated).substring(RefNames.REFS_TAGS.length());
EventKey artcKey = ArtifactEventKey.create(tagPURL(project.get(), tagName));
EiffelEvent artcEvent = publisher.getPublished(artcKey);
@@ -208,13 +217,34 @@
assertNotNull("Publisher did not find CD event", cdEvent);
assertEquals(EventKey.fromEvent(cdEvent), cdKey);
+ EventKey scsKey = SourceChangeEventKey.scsKey(project.get(), "master", getMaster());
+ EiffelEvent scsEvent = publisher.getPublished(scsKey);
+ assertNotNull("Publisher did not find SCS event", scsEvent);
+ assertEquals(EventKey.fromEvent(scsEvent), scsKey);
+
assertArtcLinks(cdEvent.meta.id, artcEvent.links);
- assertCdLinks(parentEventId, cdEvent.links);
+ assertCdLinks(scsEvent.meta.id, cdEvent.links);
}
@Test
- public void annotatedTagCreatedResultsInEvent() throws Exception {
+ public void tagCreatedResultsInNoEventWhenBranchIsBlocked() throws Exception {
+ TestEventsFilterProvider.setBlockedRefPatterns("refs/heads/master");
+ String tagName = createTagRef(true).substring(RefNames.REFS_TAGS.length());
+
+ EventKey artcKey = ArtifactEventKey.create(tagPURL(project.get(), tagName));
+ publisher.assertNotPublished(artcKey, "Publisher found ARTC event");
+
+ EventKey cdKey = CompositionDefinedEventKey.create(tagCompositionName(project.get()), tagName);
+ publisher.assertNotPublished(cdKey, "Publisher found CD event");
+
+ EventKey scsKey = SourceChangeEventKey.scsKey(project.get(), "master", getMaster());
+ publisher.assertNotPublished(scsKey, "Publisher found SCS event");
+ }
+
+ @Test
+ public void tagCreatedResultsInNoEventWhenBranchIsBlockedSCSHandled() throws Exception {
UUID parentEventId = markMasterAsHandled(SCS);
+ TestEventsFilterProvider.setBlockedRefPatterns("refs/heads/master");
String tagName = createTagRef(true).substring(RefNames.REFS_TAGS.length());
EventKey artcKey = ArtifactEventKey.create(tagPURL(project.get(), tagName));
@@ -270,10 +300,8 @@
return originMaster;
}
- public static class TestEventListenerConfigProvider implements Provider<EventListenersConfig> {
+ public static class TestEventListenersConfigProvider implements Provider<EventListenersConfig> {
private static boolean enabled;
- private static String[] refPatterns;
- private static String[] projectPatterns;
static {
reset();
@@ -281,15 +309,6 @@
static void reset() {
enabled = true;
- refPatterns = projectPatterns = new String[0];
- }
-
- static void setBlockedRefPatterns(String... patterns) {
- refPatterns = patterns;
- }
-
- static void setBlockedProjectPatterns(String... patterns) {
- projectPatterns = patterns;
}
static void disable() {
@@ -302,8 +321,7 @@
@Override
public EventListenersConfig get() {
- return new EventListenersConfig(
- enabled, toCombinedMatcher(projectPatterns), toCombinedMatcher(refPatterns));
+ return new EventListenersConfig(enabled);
}
}
@@ -312,7 +330,8 @@
@Override
protected void configure() {
install(new EiffelEventsTestModule());
- bind(EventListenersConfig.class).toProvider(TestEventListenerConfigProvider.class);
+ bind(EventListenersConfig.class).toProvider(TestEventListenersConfigProvider.class);
+ bind(EventsFilter.class).toProvider(TestEventsFilterProvider.class);
DynamicSet.bind(binder(), RevisionCreatedListener.class).to(PatchsetCreatedListener.class);
DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(RefUpdateListener.class);
bind(EiffelConfig.class).toProvider(EiffelConfig.Provider.class).in(Scopes.SINGLETON);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
index 668bb8e..e11ee3d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
@@ -24,6 +24,7 @@
import com.google.gerrit.acceptance.TestPlugin;
import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.acceptance.config.GlobalPluginConfig;
+import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.extensions.common.AccountInfo;
import com.googlesource.gerrit.plugins.eventseiffel.TestEventHub;
import com.googlesource.gerrit.plugins.eventseiffel.TestEventStorage;
@@ -48,6 +49,7 @@
public void setUp() {
eventParser = plugin.getSysInjector().getInstance(EiffelEventParserImpl.class);
TestEventHub.EVENTS.clear();
+ TestEventsFilterProvider.reset();
}
@Test
@@ -225,14 +227,66 @@
}
@Test
- public void artcNotCreatedWhenMissingScs() throws Exception {
- String tag =
+ public void artcQueued() throws Exception {
+ String ref =
+ createTagRef(getHead(repo(), "HEAD").getName(), true).substring(Constants.R_TAGS.length());
+
+ SourceChangeEventKey scc =
+ SourceChangeEventKey.sccKey(project.get(), getHead(), getHeadRevision());
+ SourceChangeEventKey scs = scc.copy(SCS);
+ ArtifactEventKey artc = ArtifactEventKey.create(tagPURL(project.get(), ref, "localhost"));
+ CompositionDefinedEventKey cd =
+ CompositionDefinedEventKey.create(tagCompositionName(project.get(), "localhost"), ref);
+
+ eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, false);
+ assertEquals(4, TestEventHub.EVENTS.size());
+ assertCorrectEvent(0, scc);
+ assertCorrectEvent(1, scs);
+ assertCorrectEvent(2, cd);
+ assertCorrectEvent(3, artc);
+ }
+
+ @Test
+ public void artcQueuedBlockBranch() throws Exception {
+ TestEventsFilterProvider.setBlockedRefPatterns("refs/heads/master");
+ String ref =
createTagRef(getHead(repo(), "HEAD").getName(), true).substring(Constants.R_TAGS.length());
EventParsingException thrown =
assertThrows(
EventParsingException.class,
- () -> eventParser.createAndScheduleArtc(project.get(), tag, EPOCH_MILLIS, false));
- assertThat(thrown).hasMessageThat().contains("Failed to find SCS for");
+ () -> eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, false));
+ assertThat(thrown).hasMessageThat().startsWith("Could not find any unblocked branch for SCS");
+ }
+
+ @Test
+ public void artcQueuedBlockBranchButReachableFromOtherBranch() throws Exception {
+ TestEventsFilterProvider.setBlockedRefPatterns("refs/heads/master");
+ createBranch(BranchNameKey.create(project, "other-branch"));
+ String ref =
+ createTagRef(getHead(repo(), "HEAD").getName(), true).substring(Constants.R_TAGS.length());
+
+ SourceChangeEventKey scc =
+ SourceChangeEventKey.sccKey(project.get(), "other-branch", getHeadRevision());
+ SourceChangeEventKey scs = scc.copy(SCS);
+ ArtifactEventKey artc = ArtifactEventKey.create(tagPURL(project.get(), ref, "localhost"));
+ CompositionDefinedEventKey cd =
+ CompositionDefinedEventKey.create(tagCompositionName(project.get(), "localhost"), ref);
+
+ eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, false);
+ assertEquals(4, TestEventHub.EVENTS.size());
+ assertCorrectEvent(0, scc);
+ assertCorrectEvent(1, scs);
+ assertCorrectEvent(2, cd);
+ assertCorrectEvent(3, artc);
+ }
+
+ @Test
+ public void artcQueuedNoTagCreated() throws Exception {
+ EventParsingException thrown =
+ assertThrows(
+ EventParsingException.class,
+ () -> eventParser.createAndScheduleArtc(project.get(), TAG_NAME, EPOCH_MILLIS, false));
+ assertThat(thrown).hasMessageThat().startsWith("Cannot find tag");
}
@Test
@@ -246,6 +300,23 @@
}
@Test
+ public void annotatedTagArtcQueuedscsHandledLightWeightBlocked() throws Exception {
+ TestEventsFilterProvider.blockLightWeightTags();
+ assertArtcQueuedScsHandled(true);
+ }
+
+ @Test
+ public void lightWeightTagArtcQueuedscsHandledLightWeightBlocked() throws Exception {
+ setScsHandled();
+ TestEventsFilterProvider.blockLightWeightTags();
+ String ref =
+ createTagRef(getHead(repo(), "HEAD").getName(), false).substring(Constants.R_TAGS.length());
+
+ eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, false);
+ assertEquals(0, TestEventHub.EVENTS.size());
+ }
+
+ @Test
public void artcQueuedCdHandled() throws Exception {
String ref = setCdHandled();
eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, false);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingTest.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingTest.java
index a0e8d8a..a606e14 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingTest.java
@@ -5,8 +5,6 @@
import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventsTest;
import com.googlesource.gerrit.plugins.eventseiffel.TestEventHub;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey;
-import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey;
-import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.junit.Ignore;
@@ -41,20 +39,4 @@
EventKey actual = EventKey.fromEvent(TestEventHub.EVENTS.get(order));
assertEquals(expected, actual);
}
-
- protected void setScsHandled() throws Exception {
- markAsHandled(eventForHead(EiffelEventType.SCS), getHead(repo(), "HEAD"));
- }
-
- protected SourceChangeEventKey eventForHead(EiffelEventType type) throws Exception {
- return SourceChangeEventKey.create(project.get(), getHead(), getHeadRevision(), type);
- }
-
- protected String getHead() throws Exception {
- return gApi.projects().name(project.get()).head();
- }
-
- protected String getHeadRevision() throws Exception {
- return getHead(repo(), "HEAD").getName();
- }
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/ParsingTestModule.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/ParsingTestModule.java
index f3fe7e5..b01640d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/ParsingTestModule.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/ParsingTestModule.java
@@ -4,12 +4,14 @@
import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventHub;
+import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventsTest.TestEventsFilterProvider;
import com.googlesource.gerrit.plugins.eventseiffel.TestEventHub;
import com.googlesource.gerrit.plugins.eventseiffel.TestEventStorage;
import com.googlesource.gerrit.plugins.eventseiffel.cache.EiffelEventIdCacheImpl;
import com.googlesource.gerrit.plugins.eventseiffel.config.EiffelConfig;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventIdCacheConfig;
import com.googlesource.gerrit.plugins.eventseiffel.config.EventMappingConfig;
+import com.googlesource.gerrit.plugins.eventseiffel.config.EventsFilter;
import com.googlesource.gerrit.plugins.eventseiffel.eiffel.api.EventStorage;
import com.googlesource.gerrit.plugins.eventseiffel.mapping.EiffelEventFactory;
import com.googlesource.gerrit.plugins.eventseiffel.mapping.EiffelEventMapper;
@@ -21,6 +23,7 @@
protected void configure() {
bind(EventStorage.class).toProvider(TestEventStorage.Provider.class).in(Singleton.class);
bind(EventIdCacheConfig.class).toProvider(EventIdCacheConfig.Provider.class);
+ bind(EventsFilter.class).toProvider(TestEventsFilterProvider.class);
install(EiffelEventIdCacheImpl.module());
bind(EiffelEventHub.class).to(TestEventHub.class);
bind(EventMappingConfig.class).toProvider(EventMappingConfig.Provider.class);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/rest/EventsEiffelRestIT.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/rest/EventsEiffelRestIT.java
index cb77c91..e1c4598 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/rest/EventsEiffelRestIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/rest/EventsEiffelRestIT.java
@@ -120,7 +120,6 @@
@Test
public void createArtcAsAdmin() throws Exception {
- createScss("master", true).assertStatus(202);
String tagName = createTagRef(true).substring(RefNames.REFS_TAGS.length());
createArtcs(tagName, true).assertStatus(202);
ArtifactEventKey artc = ArtifactEventKey.create(tagPURL(project.get(), tagName));
@@ -130,7 +129,6 @@
@Test
public void createArtcAsNonAdminForbidden() throws Exception {
- createScss("master", true).assertStatus(202);
String tagName = createTagRef(true).substring(RefNames.REFS_TAGS.length());
createArtcs(tagName, false).assertStatus(403);
publisher.assertNotPublished(