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 <eduard.heimbuch@cloudogu.com>
This commit is contained in:
Sebastian Sdorra
2021-02-26 09:49:34 +01:00
committed by GitHub
parent c8621061bf
commit 888f5d699b
24 changed files with 252 additions and 144 deletions

View File

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

View File

@@ -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<Object> 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<Object> getPendingEvents() {
return Collections.unmodifiableCollection(pendingEvents);
}
}

View File

@@ -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<RepositoryHookEvent> 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(),