mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-02 11:35:57 +01:00
Post receive hook after import (#1544)
Fire post receive repository hook event after pull from remote and after unbundle (Git, HG and SVN) Co-authored-by: René Pfeuffer <rene.pfeuffer@cloudogu.com>
This commit is contained in:
@@ -24,8 +24,6 @@
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -46,49 +44,34 @@ import java.util.List;
|
||||
|
||||
import static sonia.scm.repository.SvnUtil.parseRevision;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
public class SvnLogCommand extends AbstractSvnCommand implements LogCommand {
|
||||
|
||||
public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SvnLogCommand.class);
|
||||
|
||||
/**
|
||||
* the logger for SvnLogCommand
|
||||
*/
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(SvnLogCommand.class);
|
||||
|
||||
SvnLogCommand(SvnContext context)
|
||||
{
|
||||
SvnLogCommand(SvnContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Changeset getChangeset(String revision, LogCommandRequest request) {
|
||||
Changeset changeset = null;
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("fetch changeset {}", revision);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("fetch changeset {}", revision);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
long revisioNumber = parseRevision(revision, repository);
|
||||
Preconditions.checkArgument(revisioNumber > 0, "revision must be greater than zero: %d", revisioNumber);
|
||||
SVNRepository repo = open();
|
||||
Collection<SVNLogEntry> entries = repo.log(null, null, revisioNumber,
|
||||
revisioNumber, true, true);
|
||||
revisioNumber, true, true);
|
||||
|
||||
if (Util.isNotEmpty(entries))
|
||||
{
|
||||
if (Util.isNotEmpty(entries)) {
|
||||
changeset = SvnUtil.createChangeset(entries.iterator().next());
|
||||
}
|
||||
}
|
||||
catch (SVNException ex)
|
||||
{
|
||||
} catch (SVNException ex) {
|
||||
throw new InternalRepositoryException(repository, "could not open repository", ex);
|
||||
}
|
||||
|
||||
@@ -98,73 +81,48 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChangesetPagingResult getChangesets(LogCommandRequest request) {
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("fetch changesets for {}", request);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("fetch changesets for {}", request);
|
||||
}
|
||||
|
||||
ChangesetPagingResult changesets = null;
|
||||
ChangesetPagingResult changesets;
|
||||
int start = request.getPagingStart();
|
||||
int limit = request.getPagingLimit();
|
||||
long startRevision = parseRevision(request.getStartChangeset(), repository);
|
||||
long endRevision = parseRevision(request.getEndChangeset(), repository);
|
||||
String[] pathArray = null;
|
||||
|
||||
if (!Strings.isNullOrEmpty(request.getPath()))
|
||||
{
|
||||
pathArray = new String[] { request.getPath() };
|
||||
if (!Strings.isNullOrEmpty(request.getPath())) {
|
||||
pathArray = new String[]{request.getPath()};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
SVNRepository repo = open();
|
||||
|
||||
if ((startRevision > 0) || (pathArray != null))
|
||||
{
|
||||
if ((startRevision > 0) || (pathArray != null)) {
|
||||
changesets = getChangesets(repo, startRevision, endRevision, start,
|
||||
limit, pathArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
changesets = getChangesets(repo, start, limit);
|
||||
}
|
||||
}
|
||||
catch (SVNException ex)
|
||||
{
|
||||
} catch (SVNException ex) {
|
||||
throw new InternalRepositoryException(repository, "could not open repository", ex);
|
||||
}
|
||||
|
||||
return changesets;
|
||||
}
|
||||
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repo
|
||||
* @param start
|
||||
* @param limit
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws SVNException
|
||||
*/
|
||||
private ChangesetPagingResult getChangesets(SVNRepository repo, int start,
|
||||
int limit)
|
||||
throws SVNException
|
||||
{
|
||||
int limit)
|
||||
throws SVNException {
|
||||
long latest = repo.getLatestRevision();
|
||||
long startRev = latest - start;
|
||||
long endRev = Math.max(startRev - (limit - 1), 1);
|
||||
|
||||
final List<Changeset> changesets = Lists.newArrayList();
|
||||
|
||||
if (startRev > 0)
|
||||
{
|
||||
logger.debug("fetch changeset from {} to {}", startRev, endRev);
|
||||
if (startRev > 0) {
|
||||
LOG.debug("fetch changeset from {} to {}", startRev, endRev);
|
||||
repo.log(null, startRev, endRev, true, true,
|
||||
new ChangesetCollector(changesets));
|
||||
}
|
||||
@@ -172,51 +130,30 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
|
||||
return new ChangesetPagingResult((int) latest, changesets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repo
|
||||
* @param startRevision
|
||||
* @param endRevision
|
||||
* @param start
|
||||
* @param limit
|
||||
* @param path
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws SVNException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private ChangesetPagingResult getChangesets(SVNRepository repo,
|
||||
long startRevision, long endRevision, int start, int limit, String[] path)
|
||||
throws SVNException
|
||||
{
|
||||
long startRevision, long endRevision, int start, int limit, String[] path)
|
||||
throws SVNException {
|
||||
long startRev;
|
||||
long endRev = Math.max(endRevision, 0);
|
||||
long maxRev = repo.getLatestRevision();
|
||||
|
||||
if (startRevision >= 0l)
|
||||
{
|
||||
if (startRevision >= 0) {
|
||||
startRev = startRevision;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
startRev = maxRev;
|
||||
}
|
||||
|
||||
List<SVNLogEntry> changesetList = Lists.newArrayList();
|
||||
|
||||
logger.debug("fetch changeset from {} to {} for path {}", startRev, endRev,
|
||||
LOG.debug("fetch changeset from {} to {} for path {}", startRev, endRev,
|
||||
path);
|
||||
|
||||
Collection<SVNLogEntry> entries = repo.log(path, null, startRev, endRev,
|
||||
true, true);
|
||||
true, true);
|
||||
|
||||
for (SVNLogEntry entry : entries)
|
||||
{
|
||||
if (entry.getRevision() <= maxRev)
|
||||
{
|
||||
for (SVNLogEntry entry : entries) {
|
||||
if (entry.getRevision() <= maxRev) {
|
||||
changesetList.add(entry);
|
||||
}
|
||||
}
|
||||
@@ -225,17 +162,15 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
|
||||
int max = limit + start;
|
||||
int end = total;
|
||||
|
||||
if ((max > 0) && (end > max))
|
||||
{
|
||||
if ((max > 0) && (end > max)) {
|
||||
end = max;
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
{
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
logger.trace(
|
||||
LOG.trace(
|
||||
"create sublist from {} to {} of total {} collected changesets", start,
|
||||
end, total);
|
||||
|
||||
@@ -245,45 +180,20 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
|
||||
SvnUtil.createChangesets(changesetList));
|
||||
}
|
||||
|
||||
//~--- inner classes --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Collect and convert changesets.
|
||||
*
|
||||
*/
|
||||
private static class ChangesetCollector implements ISVNLogEntryHandler
|
||||
{
|
||||
private static class ChangesetCollector implements ISVNLogEntryHandler {
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
*
|
||||
* @param changesets
|
||||
*/
|
||||
public ChangesetCollector(Collection<Changeset> changesets)
|
||||
{
|
||||
private final Collection<Changeset> changesets;
|
||||
|
||||
public ChangesetCollector(Collection<Changeset> changesets) {
|
||||
this.changesets = changesets;
|
||||
}
|
||||
|
||||
//~--- methods ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param logEntry
|
||||
*
|
||||
* @throws SVNException
|
||||
*/
|
||||
@Override
|
||||
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException
|
||||
{
|
||||
public void handleLogEntry(SVNLogEntry logEntry) {
|
||||
changesets.add(SvnUtil.createChangeset(logEntry));
|
||||
}
|
||||
|
||||
//~--- fields -------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private final Collection<Changeset> changesets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,23 +26,21 @@ 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;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.repository.api.HookContextFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class SvnRepositoryServiceProvider extends RepositoryServiceProvider
|
||||
{
|
||||
public class SvnRepositoryServiceProvider extends RepositoryServiceProvider {
|
||||
|
||||
/** Field description */
|
||||
//J-
|
||||
public static final Set<Command> COMMANDS = ImmutableSet.of(
|
||||
Command.BLAME, Command.BROWSE, Command.CAT, Command.DIFF,
|
||||
@@ -50,101 +48,55 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider
|
||||
);
|
||||
//J+
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
@Inject
|
||||
private final SvnContext context;
|
||||
private final SvnWorkingCopyFactory workingCopyFactory;
|
||||
private final HookContextFactory hookContextFactory;
|
||||
private final ScmEventBus eventBus;
|
||||
|
||||
SvnRepositoryServiceProvider(SvnRepositoryHandler handler,
|
||||
Repository repository, SvnWorkingCopyFactory workingCopyFactory)
|
||||
{
|
||||
Repository repository,
|
||||
SvnWorkingCopyFactory workingCopyFactory,
|
||||
HookContextFactory hookContextFactory,
|
||||
ScmEventBus eventBus) {
|
||||
this.context = new SvnContext(repository, handler.getDirectory(repository.getId()));
|
||||
this.workingCopyFactory = workingCopyFactory;
|
||||
this.hookContextFactory = hookContextFactory;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
public void close() throws IOException {
|
||||
Closeables.close(context, true);
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public SvnBlameCommand getBlameCommand()
|
||||
{
|
||||
public SvnBlameCommand getBlameCommand() {
|
||||
return new SvnBlameCommand(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public SvnBrowseCommand getBrowseCommand()
|
||||
{
|
||||
public SvnBrowseCommand getBrowseCommand() {
|
||||
return new SvnBrowseCommand(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public BundleCommand getBundleCommand()
|
||||
{
|
||||
public BundleCommand getBundleCommand() {
|
||||
return new SvnBundleCommand(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public SvnCatCommand getCatCommand()
|
||||
{
|
||||
public SvnCatCommand getCatCommand() {
|
||||
return new SvnCatCommand(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public SvnDiffCommand getDiffCommand()
|
||||
{
|
||||
public SvnDiffCommand getDiffCommand() {
|
||||
return new SvnDiffCommand(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public SvnLogCommand getLogCommand()
|
||||
{
|
||||
public SvnLogCommand getLogCommand() {
|
||||
return new SvnLogCommand(context);
|
||||
}
|
||||
|
||||
@@ -163,34 +115,13 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider
|
||||
return new SvnLookupCommand(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Set<Command> getSupportedCommands()
|
||||
{
|
||||
public Set<Command> getSupportedCommands() {
|
||||
return COMMANDS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public UnbundleCommand getUnbundleCommand()
|
||||
{
|
||||
return new SvnUnbundleCommand(context);
|
||||
public UnbundleCommand getUnbundleCommand() {
|
||||
return new SvnUnbundleCommand(context, hookContextFactory, eventBus, new SvnLogCommand(context));
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private final SvnContext context;
|
||||
|
||||
private final SvnWorkingCopyFactory workingCopyFactory;
|
||||
}
|
||||
|
||||
@@ -25,21 +25,31 @@
|
||||
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;
|
||||
import sonia.scm.repository.SvnWorkingCopyFactory;
|
||||
import sonia.scm.repository.api.HookContextFactory;
|
||||
|
||||
@Extension
|
||||
public class SvnRepositoryServiceResolver implements RepositoryServiceResolver {
|
||||
|
||||
private SvnRepositoryHandler handler;
|
||||
private SvnWorkingCopyFactory workingCopyFactory;
|
||||
private final SvnRepositoryHandler handler;
|
||||
private final SvnWorkingCopyFactory workingCopyFactory;
|
||||
private final HookContextFactory hookContextFactory;
|
||||
private final ScmEventBus eventBus;
|
||||
|
||||
@Inject
|
||||
public SvnRepositoryServiceResolver(SvnRepositoryHandler handler, SvnWorkingCopyFactory workingCopyFactory) {
|
||||
public SvnRepositoryServiceResolver(SvnRepositoryHandler handler,
|
||||
SvnWorkingCopyFactory workingCopyFactory,
|
||||
HookContextFactory hookContextFactory,
|
||||
ScmEventBus eventBus
|
||||
) {
|
||||
this.handler = handler;
|
||||
this.workingCopyFactory = workingCopyFactory;
|
||||
this.hookContextFactory = hookContextFactory;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +57,7 @@ public class SvnRepositoryServiceResolver implements RepositoryServiceResolver {
|
||||
SvnRepositoryServiceProvider provider = null;
|
||||
|
||||
if (SvnRepositoryHandler.TYPE_NAME.equalsIgnoreCase(repository.getType())) {
|
||||
provider = new SvnRepositoryServiceProvider(handler, repository, workingCopyFactory);
|
||||
provider = new SvnRepositoryServiceProvider(handler, repository, workingCopyFactory, hookContextFactory, eventBus);
|
||||
}
|
||||
|
||||
return provider;
|
||||
|
||||
@@ -24,82 +24,74 @@
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Closeables;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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;
|
||||
import sonia.scm.repository.api.HookContext;
|
||||
import sonia.scm.repository.api.HookContextFactory;
|
||||
import sonia.scm.repository.api.HookFeature;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
import sonia.scm.repository.api.UnbundleResponse;
|
||||
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static sonia.scm.repository.RepositoryHookType.POST_RECEIVE;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra <s.sdorra@gmail.com>
|
||||
*/
|
||||
public class SvnUnbundleCommand extends AbstractSvnCommand
|
||||
implements UnbundleCommand
|
||||
{
|
||||
public class SvnUnbundleCommand extends AbstractSvnCommand implements UnbundleCommand {
|
||||
|
||||
/** Field description */
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(SvnUnbundleCommand.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SvnUnbundleCommand.class);
|
||||
private final HookContextFactory hookContextFactory;
|
||||
private final ScmEventBus eventBus;
|
||||
private final SvnLogCommand svnLogCommand;
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
* @param context
|
||||
*
|
||||
*/
|
||||
public SvnUnbundleCommand(SvnContext context)
|
||||
{
|
||||
public SvnUnbundleCommand(SvnContext context,
|
||||
HookContextFactory hookContextFactory,
|
||||
ScmEventBus eventBus,
|
||||
SvnLogCommand svnLogCommand
|
||||
) {
|
||||
super(context);
|
||||
this.hookContextFactory = hookContextFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.svnLogCommand = svnLogCommand;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param request
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public UnbundleResponse unbundle(UnbundleCommandRequest request)
|
||||
throws IOException
|
||||
{
|
||||
throws IOException {
|
||||
ByteSource archive = checkNotNull(request.getArchive(),
|
||||
"archive is required");
|
||||
"archive is required");
|
||||
|
||||
logger.debug("archive repository {} to {}", context.getDirectory(),
|
||||
LOG.debug("archive repository {} to {}", context.getDirectory(),
|
||||
archive);
|
||||
|
||||
UnbundleResponse response;
|
||||
|
||||
SVNClientManager clientManager = null;
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
clientManager = SVNClientManager.newInstance();
|
||||
|
||||
SVNAdminClient adminClient = clientManager.getAdminClient();
|
||||
@@ -107,44 +99,124 @@ public class SvnUnbundleCommand extends AbstractSvnCommand
|
||||
restore(adminClient, archive, context.getDirectory());
|
||||
|
||||
response = new UnbundleResponse(context.open().getLatestRevision());
|
||||
}
|
||||
catch (SVNException ex)
|
||||
{
|
||||
} catch (SVNException ex) {
|
||||
throw new IOException("could not restore dump", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
} finally {
|
||||
SvnUtil.dispose(clientManager);
|
||||
}
|
||||
|
||||
firePostReceiveRepositoryHookEvent();
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param adminClient
|
||||
* @param dump
|
||||
* @param repository
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws SVNException
|
||||
*/
|
||||
private void restore(SVNAdminClient adminClient, ByteSource dump,
|
||||
File repository)
|
||||
throws SVNException, IOException
|
||||
{
|
||||
private void firePostReceiveRepositoryHookEvent() {
|
||||
eventBus.post(createEvent());
|
||||
}
|
||||
|
||||
private PostReceiveRepositoryHookEvent 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);
|
||||
}
|
||||
|
||||
private void restore(SVNAdminClient adminClient, ByteSource dump, File repository) throws SVNException, IOException {
|
||||
InputStream inputStream = null;
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
inputStream = dump.openBufferedStream();
|
||||
adminClient.doLoad(repository, inputStream);
|
||||
}
|
||||
finally
|
||||
{
|
||||
} finally {
|
||||
Closeables.close(inputStream, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SvnImportHookContextProvider extends HookContextProvider {
|
||||
|
||||
private final Repository repository;
|
||||
private final LogCommand logCommand;
|
||||
|
||||
private SvnImportHookContextProvider(Repository repository, SvnLogCommand logCommand) {
|
||||
this.repository = repository;
|
||||
this.logCommand = logCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<HookFeature> getSupportedFeatures() {
|
||||
return ImmutableSet.of(HookFeature.CHANGESET_PROVIDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HookChangesetProvider getChangesetProvider() {
|
||||
ChangesetResolver changesetResolver = new ChangesetResolver(repository, logCommand);
|
||||
return r -> new HookChangesetResponse(changesetResolver.call());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ChangesetResolver implements Callable<Iterable<Changeset>> {
|
||||
|
||||
private final Repository repository;
|
||||
private final LogCommand logCommand;
|
||||
|
||||
ChangesetResolver(Repository repository, LogCommand logCommand) {
|
||||
this.repository = repository;
|
||||
this.logCommand = logCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Changeset> call() {
|
||||
return SingleLogRequestChangesetIterator::new;
|
||||
}
|
||||
|
||||
private class SingleLogRequestChangesetIterator implements Iterator<Changeset> {
|
||||
|
||||
private int currentNumber = 0;
|
||||
private Changeset nextChangeset;
|
||||
|
||||
SingleLogRequestChangesetIterator() {
|
||||
prefetch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nextChangeset != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Changeset next() {
|
||||
if (nextChangeset == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
Changeset currentChangeset = nextChangeset;
|
||||
prefetch();
|
||||
return currentChangeset;
|
||||
}
|
||||
|
||||
private void prefetch() {
|
||||
try {
|
||||
List<Changeset> changesets = fetchSingleChangesetPage();
|
||||
if (changesets.isEmpty()) {
|
||||
nextChangeset = null;
|
||||
} else {
|
||||
nextChangeset = changesets.get(0);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ImportFailedException(
|
||||
ContextEntry.ContextBuilder.entity(repository).build(),
|
||||
"Could not provide changeset nr " + currentNumber + " for imported repository",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Changeset> fetchSingleChangesetPage() throws IOException {
|
||||
LogCommandRequest request = new LogCommandRequest();
|
||||
request.setPagingStart(currentNumber);
|
||||
request.setPagingLimit(1);
|
||||
List<Changeset> changesets = logCommand.getChangesets(request).getChangesets();
|
||||
currentNumber = currentNumber + 1;
|
||||
return changesets;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,77 +24,101 @@
|
||||
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.Files;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
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.RepositoryTestData;
|
||||
import sonia.scm.repository.SvnUtil;
|
||||
import sonia.scm.repository.api.HookChangesetBuilder;
|
||||
import sonia.scm.repository.api.HookContext;
|
||||
import sonia.scm.repository.api.HookContextFactory;
|
||||
import sonia.scm.repository.api.UnbundleResponse;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
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;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
public class SvnUnbundleCommandTest extends AbstractSvnCommandTestBase {
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
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<PostReceiveRepositoryHookEvent> 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);
|
||||
when(hookContextFactory.createContext(any(), eq(repository))).thenReturn(hookContext);
|
||||
when(hookContext.getChangesetProvider()).thenReturn(hookChangesetBuilder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnbundle()
|
||||
throws IOException, SVNException
|
||||
{
|
||||
public void shouldFirePostCommitEventAfterUnbundle() 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)
|
||||
UnbundleResponse res = new SvnUnbundleCommand(ctx, hookContextFactory, eventBus, logCommand)
|
||||
.unbundle(new UnbundleCommandRequest(Files.asByteSource(bundle))
|
||||
);
|
||||
);
|
||||
//J+
|
||||
|
||||
assertThat(res, notNullValue());
|
||||
assertThat(res.getChangesetCount(), is(5l));
|
||||
|
||||
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();
|
||||
List<Changeset> changesets = event.getContext().getChangesetProvider().getChangesetList();
|
||||
assertThat(changesets).hasSize(1);
|
||||
assertThat(changesets).contains(first);
|
||||
|
||||
assertThat(repo.getLatestRevision(), is(5l));
|
||||
SvnUtil.closeSession(repo);
|
||||
}
|
||||
|
||||
private File bundle() throws IOException
|
||||
{
|
||||
private File bundle() throws IOException {
|
||||
File file = tempFolder.newFile();
|
||||
|
||||
//J-
|
||||
new SvnBundleCommand(createContext())
|
||||
.bundle(new BundleCommandRequest(Files.asByteSink(file))
|
||||
);
|
||||
);
|
||||
//J+
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws SVNException
|
||||
*/
|
||||
private SvnContext createEmptyContext() throws IOException, SVNException
|
||||
{
|
||||
private SvnContext createEmptyContext() throws IOException, SVNException {
|
||||
File folder = tempFolder.newFolder();
|
||||
|
||||
SVNRepositoryFactory.createLocalRepository(folder, true, true);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
mock-maker-inline
|
||||
Reference in New Issue
Block a user