From 888f5d699b813ab4daba3fc4ba18fbcbe01413c2 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Fri, 26 Feb 2021 09:49:34 +0100 Subject: [PATCH] Fire RepositoryImportHookEvent instead of PostReceiveRepositoryHookEvent (#1561) We will fire an RepositoryImportHookEvent instead of PostReceiveRepositoryHookEvent for repository imports with metadata. The event is only fired if all parts of the repository could be successfully imported. The extra event is required to avoid heavy recalculations which can be triggered by the PostReceiveRepositoryHookEvent for example the scm-statistic-plugin uses the PostReceiveRepositoryHookEvent to calculate its statistics. Co-authored-by: Eduard Heimbuch --- .../repository/ImportRepositoryHookEvent.java | 45 ++++++++++++++++++ .../api/UnbundleCommandBuilder.java | 24 +++++++++- .../spi/UnbundleCommandRequest.java | 46 +++++++++++-------- .../scm/repository/spi/GitPullCommand.java | 4 +- ...ava => GitRepositoryHookEventFactory.java} | 10 ++-- .../repository/spi/GitUnbundleCommand.java | 19 ++++---- .../spi/AbstractRemoteCommandTestBase.java | 4 +- ...ReceiveRepositoryHookEventFactoryTest.java | 8 ++-- .../spi/GitUnbundleCommandTest.java | 21 ++++----- .../scm/repository/spi/HgPullCommand.java | 4 +- ...java => HgRepositoryHookEventFactory.java} | 10 ++-- .../spi/HgRepositoryServiceProvider.java | 6 +-- .../spi/HgRepositoryServiceResolver.java | 4 +- .../scm/repository/spi/HgUnbundleCommand.java | 18 ++++---- ...ReceiveRepositoryHookEventFactoryTest.java | 7 +-- .../repository/spi/HgUnbundleCommandTest.java | 20 ++++---- .../spi/SvnRepositoryServiceProvider.java | 8 +--- .../spi/SvnRepositoryServiceResolver.java | 9 +--- .../repository/spi/SvnUnbundleCommand.java | 16 ++----- .../spi/SvnUnbundleCommandTest.java | 31 +++++-------- .../FullScmRepositoryImporter.java | 16 +++++-- .../sonia/scm/importexport/ImportState.java | 12 +++++ .../importexport/RepositoryImportStep.java | 16 ++++++- .../FullScmRepositoryImporterTest.java | 38 ++++++++++++--- 24 files changed, 252 insertions(+), 144 deletions(-) create mode 100644 scm-core/src/main/java/sonia/scm/repository/ImportRepositoryHookEvent.java rename scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/{GitPostReceiveRepositoryHookEventFactory.java => GitRepositoryHookEventFactory.java} (82%) rename scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/{HgPostReceiveRepositoryHookEventFactory.java => HgRepositoryHookEventFactory.java} (80%) diff --git a/scm-core/src/main/java/sonia/scm/repository/ImportRepositoryHookEvent.java b/scm-core/src/main/java/sonia/scm/repository/ImportRepositoryHookEvent.java new file mode 100644 index 0000000000..c802958193 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/ImportRepositoryHookEvent.java @@ -0,0 +1,45 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package sonia.scm.repository; + +import sonia.scm.event.Event; + +/** + * Import receive repository hook events are fired after a repository was imported. + * This event should only be fired if the repository was imported with meta data. + * This class is wrapper of {@link RepositoryHookEvent} for the event system of + * SCM-Manager. + * + * @author Sebastian Sdorra + * @since 2.14.0 + */ +@Event +public final class ImportRepositoryHookEvent extends WrappedRepositoryHookEvent { + + public ImportRepositoryHookEvent(RepositoryHookEvent wrappedEvent) { + super(wrappedEvent); + } + +} diff --git a/scm-core/src/main/java/sonia/scm/repository/api/UnbundleCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/UnbundleCommandBuilder.java index dd1d4b60da..d65e0a738e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/UnbundleCommandBuilder.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/UnbundleCommandBuilder.java @@ -31,12 +31,14 @@ import com.google.common.io.Files; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.spi.UnbundleCommand; import sonia.scm.repository.spi.UnbundleCommandRequest; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.function.Consumer; import java.util.zip.GZIPInputStream; import static com.google.common.base.Preconditions.checkArgument; @@ -155,6 +157,20 @@ public final class UnbundleCommandBuilder return this; } + /** + * Sets a event sink to receive a {@link RepositoryHookEvent} on successful unbundle. + * The default implementation wraps the event and sends it to the event bus. + * + * @param postEventSink consumer to process the event + * @return {@code this} + * + * @since 2.14.0 + */ + public UnbundleCommandBuilder setPostEventSink(Consumer postEventSink) { + this.postEventSink = postEventSink; + return this; + } + //~--- methods -------------------------------------------------------------- /** @@ -200,7 +216,11 @@ public final class UnbundleCommandBuilder bs = source; } - return new UnbundleCommandRequest(bs); + UnbundleCommandRequest request = new UnbundleCommandRequest(bs); + if (postEventSink != null) { + request.setPostEventSink(postEventSink); + } + return request; } //~--- inner classes -------------------------------------------------------- @@ -255,4 +275,6 @@ public final class UnbundleCommandBuilder /** Field description */ private boolean compressed = false; + + private Consumer postEventSink; } diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/UnbundleCommandRequest.java b/scm-core/src/main/java/sonia/scm/repository/spi/UnbundleCommandRequest.java index 202fee4a5b..29d2e0fd3e 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/UnbundleCommandRequest.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/UnbundleCommandRequest.java @@ -21,13 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository.spi; //~--- non-JDK imports -------------------------------------------------------- import com.google.common.base.Objects; import com.google.common.io.ByteSource; +import sonia.scm.event.ScmEventBus; +import sonia.scm.repository.PostReceiveRepositoryHookEvent; +import sonia.scm.repository.RepositoryHookEvent; + +import java.util.function.Consumer; /** * Request object for the unbundle command. @@ -35,17 +40,14 @@ import com.google.common.io.ByteSource; * @author Sebastian Sdorra * @since 1.43 */ -public final class UnbundleCommandRequest -{ +public final class UnbundleCommandRequest { /** * Constructs a new unbundle command request. * - * * @param archive byte source archive */ - public UnbundleCommandRequest(ByteSource archive) - { + public UnbundleCommandRequest(ByteSource archive) { this.archive = archive; } @@ -55,15 +57,12 @@ public final class UnbundleCommandRequest * {@inheritDoc} */ @Override - public boolean equals(Object obj) - { - if (obj == null) - { + public boolean equals(Object obj) { + if (obj == null) { return false; } - if (getClass() != obj.getClass()) - { + if (getClass() != obj.getClass()) { return false; } @@ -76,8 +75,7 @@ public final class UnbundleCommandRequest * {@inheritDoc} */ @Override - public int hashCode() - { + public int hashCode() { return Objects.hashCode(archive); } @@ -86,16 +84,28 @@ public final class UnbundleCommandRequest /** * Returns the archive as {@link ByteSource}. * - * * @return {@link ByteSource} archive */ - public ByteSource getArchive() - { + public ByteSource getArchive() { return archive; } + + public Consumer getPostEventSink() { + return postEventSink; + } + + public void setPostEventSink(Consumer postEventSink) { + this.postEventSink = postEventSink; + } + //~--- fields --------------------------------------------------------------- - /** byte source archive */ + private Consumer postEventSink = event -> + ScmEventBus.getInstance().post(new PostReceiveRepositoryHookEvent(event)); + + /** + * byte source archive + */ private final ByteSource archive; } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPullCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPullCommand.java index 73130e7880..3bf5b10298 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPullCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPullCommand.java @@ -62,13 +62,13 @@ public class GitPullCommand extends AbstractGitPushOrPullCommand private static final String REF_SPEC = "refs/heads/*:refs/heads/*"; private static final Logger LOG = LoggerFactory.getLogger(GitPullCommand.class); private final ScmEventBus eventBus; - private final GitPostReceiveRepositoryHookEventFactory eventFactory; + private final GitRepositoryHookEventFactory eventFactory; @Inject public GitPullCommand(GitRepositoryHandler handler, GitContext context, ScmEventBus eventBus, - GitPostReceiveRepositoryHookEventFactory eventFactory) { + GitRepositoryHookEventFactory eventFactory) { super(handler, context); this.eventBus = eventBus; this.eventFactory = eventFactory; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPostReceiveRepositoryHookEventFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryHookEventFactory.java similarity index 82% rename from scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPostReceiveRepositoryHookEventFactory.java rename to scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryHookEventFactory.java index 3a505140ef..69b3bd2f77 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitPostReceiveRepositoryHookEventFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryHookEventFactory.java @@ -26,7 +26,6 @@ package sonia.scm.repository.spi; import sonia.scm.repository.GitChangesetConverter; import sonia.scm.repository.GitChangesetConverterFactory; -import sonia.scm.repository.PostReceiveRepositoryHookEvent; import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.Tag; import sonia.scm.repository.api.HookContext; @@ -38,18 +37,18 @@ import java.util.List; import static sonia.scm.repository.RepositoryHookType.POST_RECEIVE; -class GitPostReceiveRepositoryHookEventFactory { +class GitRepositoryHookEventFactory { private final HookContextFactory hookContextFactory; private final GitChangesetConverterFactory changesetConverterFactory; @Inject - public GitPostReceiveRepositoryHookEventFactory(HookContextFactory hookContextFactory, GitChangesetConverterFactory changesetConverterFactory) { + public GitRepositoryHookEventFactory(HookContextFactory hookContextFactory, GitChangesetConverterFactory changesetConverterFactory) { this.hookContextFactory = hookContextFactory; this.changesetConverterFactory = changesetConverterFactory; } - PostReceiveRepositoryHookEvent createEvent(GitContext gitContext, + RepositoryHookEvent createEvent(GitContext gitContext, List branches, List tags, GitLazyChangesetResolver changesetResolver @@ -57,7 +56,6 @@ class GitPostReceiveRepositoryHookEventFactory { GitChangesetConverter converter = changesetConverterFactory.create(gitContext.open()); GitImportHookContextProvider contextProvider = new GitImportHookContextProvider(converter, branches, tags, changesetResolver); HookContext context = hookContextFactory.createContext(contextProvider, gitContext.getRepository()); - RepositoryHookEvent repositoryHookEvent = new RepositoryHookEvent(context, gitContext.getRepository(), POST_RECEIVE); - return new PostReceiveRepositoryHookEvent(repositoryHookEvent); + return new RepositoryHookEvent(context, gitContext.getRepository(), POST_RECEIVE); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitUnbundleCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitUnbundleCommand.java index 14ac835a3e..100840ccc7 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitUnbundleCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitUnbundleCommand.java @@ -30,7 +30,7 @@ import org.eclipse.jgit.lib.Ref; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.ContextEntry; -import sonia.scm.event.ScmEventBus; +import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.Tag; import sonia.scm.repository.api.ImportFailedException; import sonia.scm.repository.api.UnbundleResponse; @@ -49,15 +49,11 @@ public class GitUnbundleCommand extends AbstractGitCommand implements UnbundleCo private static final Logger LOG = LoggerFactory.getLogger(GitUnbundleCommand.class); - private final ScmEventBus eventBus; - private final GitPostReceiveRepositoryHookEventFactory eventFactory; + private final GitRepositoryHookEventFactory eventFactory; @Inject - GitUnbundleCommand(GitContext context, - ScmEventBus eventBus, - GitPostReceiveRepositoryHookEventFactory eventFactory) { + GitUnbundleCommand(GitContext context, GitRepositoryHookEventFactory eventFactory) { super(context); - this.eventBus = eventBus; this.eventFactory = eventFactory; } @@ -72,18 +68,21 @@ public class GitUnbundleCommand extends AbstractGitCommand implements UnbundleCo } unbundleRepositoryFromRequest(request, repositoryDir); - firePostReceiveRepositoryHookEvent(); + fireRepositoryHookEvent(request); return new UnbundleResponse(0); } - private void firePostReceiveRepositoryHookEvent() { + private void fireRepositoryHookEvent(UnbundleCommandRequest request) { try { Git git = Git.wrap(context.open()); List branches = extractBranches(git); List tags = extractTags(git); GitLazyChangesetResolver changesetResolver = new GitLazyChangesetResolver(context.getRepository(), git); - eventBus.post(eventFactory.createEvent(context, branches, tags, changesetResolver)); + RepositoryHookEvent event = eventFactory.createEvent(context, branches, tags, changesetResolver); + if (event != null) { + request.getPostEventSink().accept(event); + } } catch (IOException | GitAPIException e) { throw new ImportFailedException( ContextEntry.ContextBuilder.entity(context.getRepository()).build(), diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java index 61de609842..5da5c8aaf4 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java @@ -80,7 +80,7 @@ public class AbstractRemoteCommandTestBase { outgoing = Git.init().setDirectory(outgoingDirectory).setBare(false).call(); eventBus = mock(ScmEventBus.class); - eventFactory = mock(GitPostReceiveRepositoryHookEventFactory.class); + eventFactory = mock(GitRepositoryHookEventFactory.class); handler = mock(GitRepositoryHandler.class); when(handler.getDirectory(incomingRepository.getId())).thenReturn( @@ -212,5 +212,5 @@ public class AbstractRemoteCommandTestBase { private ScmTransportProtocol proto; protected ScmEventBus eventBus; - protected GitPostReceiveRepositoryHookEventFactory eventFactory; + protected GitRepositoryHookEventFactory eventFactory; } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPostReceiveRepositoryHookEventFactoryTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPostReceiveRepositoryHookEventFactoryTest.java index 9aef4bffb7..6e2748e398 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPostReceiveRepositoryHookEventFactoryTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPostReceiveRepositoryHookEventFactoryTest.java @@ -30,7 +30,7 @@ import org.junit.Before; import org.junit.Test; import sonia.scm.repository.Changeset; import sonia.scm.repository.GitChangesetConverterFactory; -import sonia.scm.repository.PostReceiveRepositoryHookEvent; +import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.Tag; import sonia.scm.repository.api.HookContext; import sonia.scm.repository.api.HookContextFactory; @@ -48,7 +48,7 @@ public class GitPostReceiveRepositoryHookEventFactoryTest extends AbstractGitCom private HookContext hookContext; - private GitPostReceiveRepositoryHookEventFactory eventFactory; + private GitRepositoryHookEventFactory eventFactory; @Before public void init() { @@ -56,7 +56,7 @@ public class GitPostReceiveRepositoryHookEventFactoryTest extends AbstractGitCom hookContext = mock(HookContext.class, RETURNS_DEEP_STUBS); when(hookContextFactory.createContext(any(), eq(repository))).thenReturn(hookContext); GitChangesetConverterFactory converterFactory = mock(GitChangesetConverterFactory.class); - eventFactory = new GitPostReceiveRepositoryHookEventFactory(hookContextFactory, converterFactory); + eventFactory = new GitRepositoryHookEventFactory(hookContextFactory, converterFactory); } @Test @@ -68,7 +68,7 @@ public class GitPostReceiveRepositoryHookEventFactoryTest extends AbstractGitCom when(hookContext.getBranchProvider().getCreatedOrModified()).thenReturn(branches); when(hookContext.getTagProvider().getCreatedTags()).thenReturn(tags); - PostReceiveRepositoryHookEvent event = eventFactory.createEvent( + RepositoryHookEvent event = eventFactory.createEvent( createContext(), branches, tags, diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitUnbundleCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitUnbundleCommandTest.java index 0494b78bfb..ed296612c8 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitUnbundleCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitUnbundleCommandTest.java @@ -28,8 +28,6 @@ import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.junit.Before; import org.junit.Test; -import sonia.scm.event.ScmEventBus; -import sonia.scm.repository.PostReceiveRepositoryHookEvent; import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.RepositoryHookType; import sonia.scm.util.Archives; @@ -37,40 +35,41 @@ import sonia.scm.util.Archives; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class GitUnbundleCommandTest extends AbstractGitCommandTestBase { - private ScmEventBus eventBus; private GitUnbundleCommand unbundleCommand; - private GitPostReceiveRepositoryHookEventFactory eventFactory; + private GitRepositoryHookEventFactory eventFactory; @Before public void initUnbundleCommand() { - eventBus = mock(ScmEventBus.class); - eventFactory = mock(GitPostReceiveRepositoryHookEventFactory.class); - unbundleCommand = new GitUnbundleCommand(createContext(), eventBus, eventFactory); + eventFactory = mock(GitRepositoryHookEventFactory.class); + unbundleCommand = new GitUnbundleCommand(createContext(), eventFactory); } @Test public void shouldUnbundleRepositoryFiles() throws IOException { - when(eventFactory.createEvent(eq(createContext()), any(), any(), any())) - .thenReturn(new PostReceiveRepositoryHookEvent(new RepositoryHookEvent(null, repository, RepositoryHookType.POST_RECEIVE))); + RepositoryHookEvent event = new RepositoryHookEvent(null, repository, RepositoryHookType.POST_RECEIVE); + when(eventFactory.createEvent(eq(createContext()), any(), any(), any())).thenReturn(event); + + AtomicReference receivedEvent = new AtomicReference<>(); String filePath = "test-input"; String fileContent = "HeartOfGold"; UnbundleCommandRequest unbundleCommandRequest = createUnbundleCommandRequestForFile(filePath, fileContent); + unbundleCommandRequest.setPostEventSink(receivedEvent::set); unbundleCommand.unbundle(unbundleCommandRequest); assertFileWithContentWasCreated(createContext().getDirectory(), filePath, fileContent); - verify(eventBus).post(any(PostReceiveRepositoryHookEvent.class)); + assertThat(receivedEvent.get()).isSameAs(event); } @Test diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPullCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPullCommand.java index ba48592263..a8519ea1c8 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPullCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPullCommand.java @@ -50,13 +50,13 @@ public class HgPullCommand extends AbstractHgPushOrPullCommand implements PullCo private static final String AUTH_SECTION = "auth"; private final ScmEventBus eventBus; private final HgLazyChangesetResolver changesetResolver; - private final HgPostReceiveRepositoryHookEventFactory eventFactory; + private final HgRepositoryHookEventFactory eventFactory; public HgPullCommand(HgRepositoryHandler handler, HgCommandContext context, ScmEventBus eventBus, HgLazyChangesetResolver changesetResolver, - HgPostReceiveRepositoryHookEventFactory eventFactory + HgRepositoryHookEventFactory eventFactory ) { super(handler, context); this.eventBus = eventBus; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPostReceiveRepositoryHookEventFactory.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryHookEventFactory.java similarity index 80% rename from scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPostReceiveRepositoryHookEventFactory.java rename to scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryHookEventFactory.java index 542253345a..161a9507c2 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgPostReceiveRepositoryHookEventFactory.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryHookEventFactory.java @@ -24,7 +24,6 @@ package sonia.scm.repository.spi; -import sonia.scm.repository.PostReceiveRepositoryHookEvent; import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.Tag; import sonia.scm.repository.api.HookContext; @@ -37,21 +36,20 @@ import static sonia.scm.repository.RepositoryHookType.POST_RECEIVE; import static sonia.scm.repository.spi.HgBranchesTagsExtractor.extractBranches; import static sonia.scm.repository.spi.HgBranchesTagsExtractor.extractTags; -class HgPostReceiveRepositoryHookEventFactory { +class HgRepositoryHookEventFactory { private final HookContextFactory hookContextFactory; @Inject - public HgPostReceiveRepositoryHookEventFactory(HookContextFactory hookContextFactory) { + public HgRepositoryHookEventFactory(HookContextFactory hookContextFactory) { this.hookContextFactory = hookContextFactory; } - PostReceiveRepositoryHookEvent createEvent(HgCommandContext hgContext, HgLazyChangesetResolver changesetResolver) { + RepositoryHookEvent createEvent(HgCommandContext hgContext, HgLazyChangesetResolver changesetResolver) { List branches = extractBranches(hgContext); List tags = extractTags(hgContext); HgImportHookContextProvider contextProvider = new HgImportHookContextProvider(branches, tags, changesetResolver); HookContext context = hookContextFactory.createContext(contextProvider, hgContext.getScmRepository()); - RepositoryHookEvent repositoryHookEvent = new RepositoryHookEvent(context, hgContext.getScmRepository(), POST_RECEIVE); - return new PostReceiveRepositoryHookEvent(repositoryHookEvent); + return new RepositoryHookEvent(context, hgContext.getScmRepository(), POST_RECEIVE); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 2fe276a3d6..81ac655f6e 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -66,12 +66,12 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider { private final HgRepositoryHandler handler; private final HgCommandContext context; private final HgLazyChangesetResolver lazyChangesetResolver; - private final HgPostReceiveRepositoryHookEventFactory eventFactory; + private final HgRepositoryHookEventFactory eventFactory; private final ScmEventBus eventBus; HgRepositoryServiceProvider(HgRepositoryHandler handler, HgRepositoryFactory factory, - HgPostReceiveRepositoryHookEventFactory eventFactory, + HgRepositoryHookEventFactory eventFactory, ScmEventBus eventBus, Repository repository) { this.handler = handler; @@ -184,6 +184,6 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider { @Override public UnbundleCommand getUnbundleCommand() { - return new HgUnbundleCommand(context, eventBus, lazyChangesetResolver, eventFactory); + return new HgUnbundleCommand(context, lazyChangesetResolver, eventFactory); } } diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java index 3fd7f83378..be10913fbb 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceResolver.java @@ -40,13 +40,13 @@ public class HgRepositoryServiceResolver implements RepositoryServiceResolver { private final HgRepositoryHandler handler; private final HgRepositoryFactory factory; private final ScmEventBus eventBus; - private final HgPostReceiveRepositoryHookEventFactory eventFactory; + private final HgRepositoryHookEventFactory eventFactory; @Inject public HgRepositoryServiceResolver(HgRepositoryHandler handler, HgRepositoryFactory factory, ScmEventBus eventBus, - HgPostReceiveRepositoryHookEventFactory eventFactory + HgRepositoryHookEventFactory eventFactory ) { this.handler = handler; this.factory = factory; diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgUnbundleCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgUnbundleCommand.java index 2a6aacad97..49f6d5973b 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgUnbundleCommand.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgUnbundleCommand.java @@ -27,7 +27,7 @@ package sonia.scm.repository.spi; import com.google.common.io.ByteSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sonia.scm.event.ScmEventBus; +import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.api.UnbundleResponse; import java.io.IOException; @@ -41,17 +41,14 @@ public class HgUnbundleCommand implements UnbundleCommand { private static final Logger LOG = LoggerFactory.getLogger(HgUnbundleCommand.class); private final HgCommandContext context; - private final ScmEventBus eventBus; private final HgLazyChangesetResolver changesetResolver; - private final HgPostReceiveRepositoryHookEventFactory eventFactory; + private final HgRepositoryHookEventFactory eventFactory; HgUnbundleCommand(HgCommandContext context, - ScmEventBus eventBus, HgLazyChangesetResolver changesetResolver, - HgPostReceiveRepositoryHookEventFactory eventFactory + HgRepositoryHookEventFactory eventFactory ) { this.context = context; - this.eventBus = eventBus; this.changesetResolver = changesetResolver; this.eventFactory = eventFactory; } @@ -67,12 +64,15 @@ public class HgUnbundleCommand implements UnbundleCommand { } unbundleRepositoryFromRequest(request, repositoryDir); - firePostReceiveRepositoryHookEvent(); + fireHookEvent(request); return new UnbundleResponse(0); } - private void firePostReceiveRepositoryHookEvent() { - eventBus.post(eventFactory.createEvent(context, changesetResolver)); + private void fireHookEvent(UnbundleCommandRequest request) { + RepositoryHookEvent event = eventFactory.createEvent(context, changesetResolver); + if (event != null) { + request.getPostEventSink().accept(event); + } } private void unbundleRepositoryFromRequest(UnbundleCommandRequest request, Path repositoryDir) throws IOException { diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgPostReceiveRepositoryHookEventFactoryTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgPostReceiveRepositoryHookEventFactoryTest.java index 7851823c34..3037e76f85 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgPostReceiveRepositoryHookEventFactoryTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgPostReceiveRepositoryHookEventFactoryTest.java @@ -29,6 +29,7 @@ import org.junit.Before; import org.junit.Test; import sonia.scm.repository.Changeset; import sonia.scm.repository.PostReceiveRepositoryHookEvent; +import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.Tag; import sonia.scm.repository.api.HookContext; import sonia.scm.repository.api.HookContextFactory; @@ -43,14 +44,14 @@ public class HgPostReceiveRepositoryHookEventFactoryTest extends AbstractHgComma private HookContext hookContext; - private HgPostReceiveRepositoryHookEventFactory eventFactory; + private HgRepositoryHookEventFactory eventFactory; @Before public void init() { HookContextFactory hookContextFactory = mock(HookContextFactory.class); hookContext = mock(HookContext.class, RETURNS_DEEP_STUBS); when(hookContextFactory.createContext(any(), any())).thenReturn(hookContext); - eventFactory = new HgPostReceiveRepositoryHookEventFactory(hookContextFactory); + eventFactory = new HgRepositoryHookEventFactory(hookContextFactory); } @Test @@ -64,7 +65,7 @@ public class HgPostReceiveRepositoryHookEventFactoryTest extends AbstractHgComma HgLazyChangesetResolver changesetResolver = mock(HgLazyChangesetResolver.class); - PostReceiveRepositoryHookEvent event = eventFactory.createEvent(cmdContext, changesetResolver); + RepositoryHookEvent event = eventFactory.createEvent(cmdContext, changesetResolver); assertThat(event.getContext().getBranchProvider().getCreatedOrModified()).isSameAs(branches); assertThat(event.getContext().getTagProvider().getCreatedTags()).isSameAs(tags); diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgUnbundleCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgUnbundleCommandTest.java index a9f53bd4b9..0813aa2900 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgUnbundleCommandTest.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgUnbundleCommandTest.java @@ -30,9 +30,7 @@ import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.junit.Before; import org.junit.Test; -import sonia.scm.event.ScmEventBus; import sonia.scm.repository.HgTestUtil; -import sonia.scm.repository.PostReceiveRepositoryHookEvent; import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.RepositoryHookType; import sonia.scm.util.Archives; @@ -41,41 +39,41 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class HgUnbundleCommandTest extends AbstractHgCommandTestBase { - private ScmEventBus eventBus; private HgUnbundleCommand unbundleCommand; - private HgPostReceiveRepositoryHookEventFactory eventFactory; + private HgRepositoryHookEventFactory eventFactory; @Before public void initUnbundleCommand() { - eventBus = mock(ScmEventBus.class); - eventFactory = mock(HgPostReceiveRepositoryHookEventFactory.class); - unbundleCommand = new HgUnbundleCommand(cmdContext, eventBus, new HgLazyChangesetResolver(HgTestUtil.createFactory(handler, repositoryDirectory), null), eventFactory); + eventFactory = mock(HgRepositoryHookEventFactory.class); + unbundleCommand = new HgUnbundleCommand(cmdContext, new HgLazyChangesetResolver(HgTestUtil.createFactory(handler, repositoryDirectory), null), eventFactory); } @Test public void shouldUnbundleRepositoryFiles() throws IOException { - when(eventFactory.createEvent(eq(cmdContext), any())) - .thenReturn(new PostReceiveRepositoryHookEvent(new RepositoryHookEvent(null, repository, RepositoryHookType.POST_RECEIVE))); + RepositoryHookEvent event = new RepositoryHookEvent(null, repository, RepositoryHookType.POST_RECEIVE); + when(eventFactory.createEvent(eq(cmdContext), any())).thenReturn(event); + AtomicReference receivedEvent = new AtomicReference<>(); String filePath = "test-input"; String fileContent = "HeartOfGold"; UnbundleCommandRequest unbundleCommandRequest = createUnbundleCommandRequestForFile(filePath, fileContent); + unbundleCommandRequest.setPostEventSink(receivedEvent::set); unbundleCommand.unbundle(unbundleCommandRequest); assertFileWithContentWasCreated(cmdContext.getDirectory(), filePath, fileContent); - verify(eventBus).post(any(PostReceiveRepositoryHookEvent.class)); + assertThat(receivedEvent.get()).isSameAs(event); } @Test diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java index e6d89f419d..3ef452eb01 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java @@ -26,7 +26,6 @@ package sonia.scm.repository.spi; import com.google.common.collect.ImmutableSet; import com.google.common.io.Closeables; -import sonia.scm.event.ScmEventBus; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; import sonia.scm.repository.SvnWorkingCopyFactory; @@ -52,17 +51,14 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider { private final SvnContext context; private final SvnWorkingCopyFactory workingCopyFactory; private final HookContextFactory hookContextFactory; - private final ScmEventBus eventBus; SvnRepositoryServiceProvider(SvnRepositoryHandler handler, Repository repository, SvnWorkingCopyFactory workingCopyFactory, - HookContextFactory hookContextFactory, - ScmEventBus eventBus) { + HookContextFactory hookContextFactory) { this.context = new SvnContext(repository, handler.getDirectory(repository.getId())); this.workingCopyFactory = workingCopyFactory; this.hookContextFactory = hookContextFactory; - this.eventBus = eventBus; } @Override @@ -122,6 +118,6 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider { @Override public UnbundleCommand getUnbundleCommand() { - return new SvnUnbundleCommand(context, hookContextFactory, eventBus, new SvnLogCommand(context)); + return new SvnUnbundleCommand(context, hookContextFactory, new SvnLogCommand(context)); } } diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java index 9c66bd237b..827e3827ec 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceResolver.java @@ -25,7 +25,6 @@ package sonia.scm.repository.spi; import com.google.inject.Inject; -import sonia.scm.event.ScmEventBus; import sonia.scm.plugin.Extension; import sonia.scm.repository.Repository; import sonia.scm.repository.SvnRepositoryHandler; @@ -38,18 +37,14 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { private final SvnRepositoryHandler handler; private final SvnWorkingCopyFactory workingCopyFactory; private final HookContextFactory hookContextFactory; - private final ScmEventBus eventBus; @Inject public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnWorkingCopyFactory workingCopyFactory, - HookContextFactory hookContextFactory, - ScmEventBus eventBus - ) { + HookContextFactory hookContextFactory) { this.handler = handler; this.workingCopyFactory = workingCopyFactory; this.hookContextFactory = hookContextFactory; - this.eventBus = eventBus; } @Override @@ -57,7 +52,7 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver { SvnRepositoryServiceProvider provider = null; if (SvnRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) { - provider = new SvnRepositoryServiceProvider(handler, repository, workingCopyFactory, hookContextFactory, eventBus); + provider = new SvnRepositoryServiceProvider(handler, repository, workingCopyFactory, hookContextFactory); } return provider; diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnUnbundleCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnUnbundleCommand.java index 5bc2cd92bf..31752546bd 100644 --- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnUnbundleCommand.java +++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnUnbundleCommand.java @@ -33,9 +33,7 @@ import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.admin.SVNAdminClient; import sonia.scm.ContextEntry; -import sonia.scm.event.ScmEventBus; import sonia.scm.repository.Changeset; -import sonia.scm.repository.PostReceiveRepositoryHookEvent; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.SvnUtil; @@ -64,17 +62,14 @@ public class SvnUnbundleCommand extends AbstractSvnCommand implements UnbundleCo private static final Logger LOG = LoggerFactory.getLogger(SvnUnbundleCommand.class); private final HookContextFactory hookContextFactory; - private final ScmEventBus eventBus; private final SvnLogCommand svnLogCommand; public SvnUnbundleCommand(SvnContext context, HookContextFactory hookContextFactory, - ScmEventBus eventBus, SvnLogCommand svnLogCommand ) { super(context); this.hookContextFactory = hookContextFactory; - this.eventBus = eventBus; this.svnLogCommand = svnLogCommand; } @@ -105,19 +100,18 @@ public class SvnUnbundleCommand extends AbstractSvnCommand implements UnbundleCo SvnUtil.dispose(clientManager); } - firePostReceiveRepositoryHookEvent(); + fireHookEvent(request); return response; } - private void firePostReceiveRepositoryHookEvent() { - eventBus.post(createEvent()); + private void fireHookEvent(UnbundleCommandRequest request) { + request.getPostEventSink().accept(createEvent()); } - private PostReceiveRepositoryHookEvent createEvent() { + private RepositoryHookEvent createEvent() { Repository repository = this.context.getRepository(); HookContext context = hookContextFactory.createContext(new SvnImportHookContextProvider(repository, svnLogCommand), repository); - RepositoryHookEvent repositoryHookEvent = new RepositoryHookEvent(context, repository, POST_RECEIVE); - return new PostReceiveRepositoryHookEvent(repositoryHookEvent); + return new RepositoryHookEvent(context, repository, POST_RECEIVE); } private void restore(SVNAdminClient adminClient, ByteSource dump, File repository) throws SVNException, IOException { diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnUnbundleCommandTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnUnbundleCommandTest.java index 0495c1514e..48ea937763 100644 --- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnUnbundleCommandTest.java +++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnUnbundleCommandTest.java @@ -33,11 +33,10 @@ import org.mockito.Captor; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.SVNRepositoryFactory; -import sonia.scm.event.ScmEventBus; import sonia.scm.repository.Changeset; import sonia.scm.repository.Person; -import sonia.scm.repository.PostReceiveRepositoryHookEvent; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.RepositoryTestData; import sonia.scm.repository.SvnUtil; import sonia.scm.repository.api.HookChangesetBuilder; @@ -48,30 +47,24 @@ import sonia.scm.repository.api.UnbundleResponse; import java.io.File; import java.io.IOException; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class SvnUnbundleCommandTest extends AbstractSvnCommandTestBase { private final Repository repository = RepositoryTestData.createHeartOfGold("svn"); private HookContextFactory hookContextFactory; - private ScmEventBus eventBus; private SvnLogCommand logCommand; private HookChangesetBuilder hookChangesetBuilder; - @Captor - private final ArgumentCaptor eventCaptor = - ArgumentCaptor.forClass(PostReceiveRepositoryHookEvent.class); - @Before public void initMocks() { hookContextFactory = mock(HookContextFactory.class); - eventBus = mock(ScmEventBus.class); logCommand = mock(SvnLogCommand.class); HookContext hookContext = mock(HookContext.class); hookChangesetBuilder = mock(HookChangesetBuilder.class); @@ -80,28 +73,28 @@ public class SvnUnbundleCommandTest extends AbstractSvnCommandTestBase { } @Test - public void shouldFirePostCommitEventAfterUnbundle() throws IOException, SVNException { + public void shouldFireRepositoryHookEventAfterUnbundle() throws IOException, SVNException { Changeset first = new Changeset("1", 0L, new Person("trillian"), "first commit"); when(hookChangesetBuilder.getChangesetList()).thenReturn(ImmutableList.of(first)); File bundle = bundle(); SvnContext ctx = createEmptyContext(); - //J- - UnbundleResponse res = new SvnUnbundleCommand(ctx, hookContextFactory, eventBus, logCommand) - .unbundle(new UnbundleCommandRequest(Files.asByteSource(bundle)) - ); - //J+ + + AtomicReference eventSink = new AtomicReference<>(); + UnbundleCommandRequest request = new UnbundleCommandRequest(Files.asByteSource(bundle)); + request.setPostEventSink(eventSink::set); + + UnbundleResponse res = new SvnUnbundleCommand(ctx, hookContextFactory, logCommand) + .unbundle(request); assertThat(res).isNotNull(); assertThat(res.getChangesetCount()).isEqualTo(5); SVNRepository repo = ctx.open(); assertThat(repo.getLatestRevision()).isEqualTo(5); - verify(eventBus).post(eventCaptor.capture()); - PostReceiveRepositoryHookEvent event = eventCaptor.getValue(); + RepositoryHookEvent event = eventSink.get(); List changesets = event.getContext().getChangesetProvider().getChangesetList(); - assertThat(changesets).hasSize(1); - assertThat(changesets).contains(first); + assertThat(changesets).hasSize(1).contains(first); SvnUtil.closeSession(repo); } diff --git a/scm-webapp/src/main/java/sonia/scm/importexport/FullScmRepositoryImporter.java b/scm-webapp/src/main/java/sonia/scm/importexport/FullScmRepositoryImporter.java index 550fd7cedb..0c90aba232 100644 --- a/scm-webapp/src/main/java/sonia/scm/importexport/FullScmRepositoryImporter.java +++ b/scm-webapp/src/main/java/sonia/scm/importexport/FullScmRepositoryImporter.java @@ -31,6 +31,7 @@ import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.ContextEntry; +import sonia.scm.event.ScmEventBus; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.api.ImportFailedException; @@ -51,6 +52,7 @@ public class FullScmRepositoryImporter { private final ImportStep[] importSteps; private final RepositoryManager repositoryManager; private final RepositoryImportExportEncryption repositoryImportExportEncryption; + private final ScmEventBus eventBus; @Inject public FullScmRepositoryImporter(EnvironmentCheckStep environmentCheckStep, @@ -58,10 +60,13 @@ public class FullScmRepositoryImporter { StoreImportStep storeImportStep, RepositoryImportStep repositoryImportStep, RepositoryManager repositoryManager, - RepositoryImportExportEncryption repositoryImportExportEncryption) { + RepositoryImportExportEncryption repositoryImportExportEncryption, + ScmEventBus eventBus + ) { this.repositoryManager = repositoryManager; this.repositoryImportExportEncryption = repositoryImportExportEncryption; importSteps = new ImportStep[]{environmentCheckStep, metadataImportStep, storeImportStep, repositoryImportStep}; + this.eventBus = eventBus; } public Repository importFromStream(Repository repository, InputStream inputStream, String password) { @@ -109,12 +114,15 @@ public class FullScmRepositoryImporter { stream(importSteps).forEach(step -> step.finish(state)); return state.getRepository(); } finally { - stream(importSteps) - .forEach(step -> step.cleanup(state)); - if (!state.success()) { + stream(importSteps).forEach(step -> step.cleanup(state)); + if (state.success()) { + // send all pending events on successful import + state.getPendingEvents().forEach(eventBus::post); + } else { // Delete the repository if any error occurs during the import repositoryManager.delete(state.getRepository()); } + } } diff --git a/scm-webapp/src/main/java/sonia/scm/importexport/ImportState.java b/scm-webapp/src/main/java/sonia/scm/importexport/ImportState.java index 9e61702844..d16d220760 100644 --- a/scm-webapp/src/main/java/sonia/scm/importexport/ImportState.java +++ b/scm-webapp/src/main/java/sonia/scm/importexport/ImportState.java @@ -28,8 +28,10 @@ import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryPermission; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Optional; class ImportState { @@ -44,6 +46,8 @@ class ImportState { private Path temporaryRepositoryBundle; + private final List pendingEvents = new ArrayList<>(); + ImportState(Repository repository) { this.repository = repository; } @@ -95,4 +99,12 @@ class ImportState { public void repositoryImported() { this.repositoryImported = true; } + + public void addPendingEvent(Object event) { + this.pendingEvents.add(event); + } + + public Collection getPendingEvents() { + return Collections.unmodifiableCollection(pendingEvents); + } } diff --git a/scm-webapp/src/main/java/sonia/scm/importexport/RepositoryImportStep.java b/scm-webapp/src/main/java/sonia/scm/importexport/RepositoryImportStep.java index cb0976f773..983e397b4e 100644 --- a/scm-webapp/src/main/java/sonia/scm/importexport/RepositoryImportStep.java +++ b/scm-webapp/src/main/java/sonia/scm/importexport/RepositoryImportStep.java @@ -28,10 +28,13 @@ import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.ContextEntry; +import sonia.scm.repository.ImportRepositoryHookEvent; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.api.ImportFailedException; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; +import sonia.scm.repository.api.UnbundleCommandBuilder; import sonia.scm.repository.work.WorkdirProvider; import sonia.scm.util.IOUtil; @@ -40,6 +43,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicReference; import static sonia.scm.ContextEntry.ContextBuilder.entity; @@ -99,8 +103,18 @@ class RepositoryImportStep implements ImportStep { private void unbundleRepository(ImportState state, InputStream is) { try (RepositoryService service = serviceFactory.create(state.getRepository())) { - service.getUnbundleCommand().unbundle(new NoneClosingInputStream(is)); + AtomicReference eventSink = new AtomicReference<>(); + + UnbundleCommandBuilder unbundleCommand = service.getUnbundleCommand(); + unbundleCommand.setPostEventSink(eventSink::set); + unbundleCommand.unbundle(new NoneClosingInputStream(is)); + state.repositoryImported(); + + RepositoryHookEvent repositoryHookEvent = eventSink.get(); + if (repositoryHookEvent != null) { + state.addPendingEvent(new ImportRepositoryHookEvent(repositoryHookEvent)); + } } catch (IOException e) { throw new ImportFailedException( entity(state.getRepository()).build(), diff --git a/scm-webapp/src/test/java/sonia/scm/importexport/FullScmRepositoryImporterTest.java b/scm-webapp/src/test/java/sonia/scm/importexport/FullScmRepositoryImporterTest.java index ee915d7856..1c7d8f2d69 100644 --- a/scm-webapp/src/test/java/sonia/scm/importexport/FullScmRepositoryImporterTest.java +++ b/scm-webapp/src/test/java/sonia/scm/importexport/FullScmRepositoryImporterTest.java @@ -31,10 +31,15 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import sonia.scm.event.ScmEventBus; +import sonia.scm.repository.ImportRepositoryHookEvent; import sonia.scm.repository.Repository; +import sonia.scm.repository.RepositoryHookEvent; import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryPermission; import sonia.scm.repository.RepositoryTestData; @@ -52,6 +57,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; +import java.util.function.Consumer; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -98,6 +104,15 @@ class FullScmRepositoryImporterTest { @InjectMocks private RepositoryImportStep repositoryImportStep; + @Mock + private ScmEventBus eventBus; + + @Mock + private RepositoryHookEvent event; + + @Captor + private ArgumentCaptor> eventSinkCaptor; + private FullScmRepositoryImporter fullImporter; @BeforeEach @@ -108,7 +123,9 @@ class FullScmRepositoryImporterTest { storeImportStep, repositoryImportStep, repositoryManager, - repositoryImportExportEncryption); + repositoryImportExportEncryption, + eventBus + ); } @BeforeEach @@ -147,7 +164,7 @@ class FullScmRepositoryImporterTest { lenient().when(workdirProvider.createNewWorkdir(REPOSITORY.getId())).thenReturn(temp.toFile()); when(compatibilityChecker.check(any())).thenReturn(true); - when(repositoryManager.create(eq(REPOSITORY))).thenReturn(REPOSITORY); + when(repositoryManager.create(REPOSITORY)).thenReturn(REPOSITORY); } @Test @@ -197,13 +214,22 @@ class FullScmRepositoryImporterTest { } @Test - void shouldDecryptStreamWhenPasswordSet() throws IOException { + void shouldFireImportRepositoryHookEvent() throws IOException { InputStream stream = Resources.getResource("sonia/scm/repository/import/scm-import.tar.gz").openStream(); - when(repositoryImportExportEncryption.decrypt(any(), eq("hg2tg"))).thenAnswer(invocation -> invocation.getArgument(0)); - fullImporter.importFromStream(REPOSITORY, stream, "hg2tg"); + // capture the event sink which is registered by RepositoryImportStep + // we use when here instead of verify, because for verify we have used it before + when(unbundleCommandBuilder.setPostEventSink(eventSinkCaptor.capture())).thenReturn(unbundleCommandBuilder); + // when the RepositoryImportStep calls unbundle we pass our mocked event to the captured sink + when(unbundleCommandBuilder.unbundle(any(InputStream.class))).then(ic -> { + eventSinkCaptor.getValue().accept(event); + // RepositoryImportStep does not evaluate the return value of unbundle + return null; + }); - verify(updateEngine).update(REPOSITORY.getId()); + fullImporter.importFromStream(REPOSITORY, stream, ""); + + verify(eventBus).post(any(ImportRepositoryHookEvent.class)); } } }