Merge branch 'stable-3.4' * stable-3.4: (24 commits) ParsingQueuePersistenceIT: fix google-common imports EiffelEventParser: fix javadoc Persist failed tasks ParsingQueue: Save failed parsing-tasks Keep queued tasks to persist in a Set and not a List Correct spelling persistance -> persistence ParsingQueue: Move scheduling logic into worker Fix EiffelEventParserIt#artcQueued Refactor EiffelEventParser and implementations EiffelConfig: fix invalid log format EventKey: add missing cases to switch/case Fix event-name in routing key Persist parsing-queue on plugin stop EiffelEventParsingQueue: Google-java-format Refactor EiffelEventParserIT Make EiffelEventParsingQueue#scheduleArtcCreation private Extract private method to schedule SCS from submit-event Rename EiffelEventParser and EiffelEventParserIf Extract interface from EiffelEventParser Extract the task description from EventParsingWorker ... Change-Id: I8d6f26aef920b9b7ccd967a5f7f164a02b9c6650
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 9a089d4..4e71eb1 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
@@ -32,8 +32,10 @@ import com.google.gerrit.extensions.events.RevisionCreatedListener.Event; 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; @@ -57,6 +59,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 { @@ -68,17 +72,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) @@ -272,67 +279,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 {
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/java/com/googlesource/gerrit/plugins/eventseiffel/rest/RestModule.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/RestModule.java index 29a643e..637f764 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/RestModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/RestModule.java
@@ -18,11 +18,16 @@ import static com.google.gerrit.server.project.TagResource.TAG_KIND; import com.google.gerrit.extensions.restapi.RestApiModule; +import com.google.inject.Scopes; +import com.googlesource.gerrit.plugins.eventseiffel.config.EventListenersConfig; public class RestModule extends RestApiModule { @Override public void configure() { + bind(EventListenersConfig.class) + .toProvider(EventListenersConfig.Provider.class) + .in(Scopes.SINGLETON); post(BRANCH_KIND, "createSccs").to(CreateSccs.class); post(BRANCH_KIND, "createScss").to(CreateScss.class); post(TAG_KIND, "createArtcs").to(CreateArtcs.class);
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 126eb50..0527b19 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; @@ -38,6 +37,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; @@ -64,7 +64,8 @@ @Before public void before() { publisher = plugin.getSysInjector().getInstance(TestEventPublisher.class); - TestEventListenerConfigProvider.reset(); + TestEventsFilterProvider.reset(); + TestEventListenersConfigProvider.reset(); } @After @@ -111,13 +112,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); @@ -163,7 +164,7 @@ @Test public void noEventsCreatedWhenDisabled() throws Exception { - TestEventListenerConfigProvider.disable(); + TestEventListenersConfigProvider.disable(); PushOneCommit.Result res = createChange(); SourceChangeEventKey sccKey = toSccKey(res); EiffelEvent sccEvent = publisher.getPublished(sccKey); @@ -175,7 +176,7 @@ @Test public void noEventsCreatedWhenRefIsBlocked() throws Exception { - TestEventListenerConfigProvider.setBlockedRefPatterns("refs/heads/master"); + TestEventsFilterProvider.setBlockedRefPatterns("refs/heads/master"); PushOneCommit.Result res = createChange(); SourceChangeEventKey sccKey = toSccKey(res); EiffelEvent sccEvent = publisher.getPublished(sccKey); @@ -188,7 +189,7 @@ @Test public void noEventsCreatedWhenProjectIsBlocked() throws Exception { - TestEventListenerConfigProvider.setBlockedProjectPatterns(project.get()); + TestEventsFilterProvider.setBlockedProjectPatterns(project.get()); PushOneCommit.Result res = createChange(); SourceChangeEventKey sccKey = toSccKey(res); EiffelEvent sccEvent = publisher.getPublished(sccKey); @@ -200,8 +201,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); @@ -213,13 +222,37 @@ 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)); + EiffelEvent artcEvent = publisher.getPublished(artcKey); + assertNull("Publisher found ARTC event", artcEvent); + + EventKey cdKey = CompositionDefinedEventKey.create(tagCompositionName(project.get()), tagName); + EiffelEvent cdEvent = publisher.getPublished(cdKey); + assertNull("Publisher found CD event", cdEvent); + + EventKey scsKey = SourceChangeEventKey.scsKey(project.get(), "master", getMaster()); + EiffelEvent scsEvent = publisher.getPublished(scsKey); + assertNull("Publisher found SCS event", scsEvent); + } + + @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)); @@ -275,10 +308,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(); @@ -286,15 +317,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() { @@ -307,8 +329,7 @@ @Override public EventListenersConfig get() { - return new EventListenersConfig( - enabled, toCombinedMatcher(projectPatterns), toCombinedMatcher(refPatterns)); + return new EventListenersConfig(enabled); } } @@ -317,7 +338,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 d483a66..691acf1 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
@@ -123,7 +123,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)); @@ -133,7 +132,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); ArtifactEventKey artc = ArtifactEventKey.create(tagPURL(project.get(), tagName));