mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-03-05 03:40:56 +01:00
Move import logic to dedicated classes
This commit is contained in:
@@ -90,5 +90,6 @@ public class MapperModule extends AbstractModule {
|
||||
bind(ApiKeyToApiKeyDtoMapper.class).to(Mappers.getMapperClass(ApiKeyToApiKeyDtoMapper.class));
|
||||
|
||||
bind(RepositoryExportInformationToDtoMapper.class).to(Mappers.getMapperClass(RepositoryExportInformationToDtoMapper.class));
|
||||
bind(RepositoryImportDtoToRepositoryImportParametersMapper.class).to(Mappers.getMapperClass(RepositoryImportDtoToRepositoryImportParametersMapper.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
import static sonia.scm.api.v2.resources.RepositoryTypeSupportChecker.checkSupport;
|
||||
import static sonia.scm.api.v2.resources.RepositoryTypeSupportChecker.type;
|
||||
import static sonia.scm.importexport.RepositoryTypeSupportChecker.checkSupport;
|
||||
import static sonia.scm.importexport.RepositoryTypeSupportChecker.type;
|
||||
|
||||
public class RepositoryExportResource {
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.api.v2.resources;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import sonia.scm.importexport.FromUrlImporter;
|
||||
|
||||
@Mapper
|
||||
public interface RepositoryImportDtoToRepositoryImportParametersMapper {
|
||||
FromUrlImporter.RepositoryImportParameters map(RepositoryImportResource.RepositoryImportFromUrlDto dto);
|
||||
}
|
||||
@@ -27,10 +27,8 @@ package sonia.scm.api.v2.resources;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.inject.Inject;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
@@ -39,30 +37,20 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
|
||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
||||
import org.jboss.resteasy.plugins.providers.multipart.MultipartInputImpl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.ContextEntry;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.importexport.FromBundleImporter;
|
||||
import sonia.scm.importexport.FromUrlImporter;
|
||||
import sonia.scm.importexport.FullScmRepositoryImporter;
|
||||
import sonia.scm.importexport.RepositoryImportExportEncryption;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryImportEvent;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
import sonia.scm.repository.api.PullCommandBuilder;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.util.IOUtil;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
import sonia.scm.web.api.DtoValidator;
|
||||
|
||||
@@ -80,46 +68,40 @@ import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static sonia.scm.api.v2.resources.RepositoryTypeSupportChecker.checkSupport;
|
||||
import static sonia.scm.api.v2.resources.RepositoryTypeSupportChecker.type;
|
||||
|
||||
public class RepositoryImportResource {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RepositoryImportResource.class);
|
||||
|
||||
private final RepositoryManager manager;
|
||||
private final RepositoryDtoToRepositoryMapper mapper;
|
||||
private final RepositoryServiceFactory serviceFactory;
|
||||
private final ResourceLinks resourceLinks;
|
||||
private final ScmEventBus eventBus;
|
||||
private final FullScmRepositoryImporter fullScmRepositoryImporter;
|
||||
private final RepositoryImportExportEncryption repositoryImportExportEncryption;
|
||||
private final RepositoryImportDtoToRepositoryImportParametersMapper importParametersMapper;
|
||||
private final FromUrlImporter fromUrlImporter;
|
||||
private final FromBundleImporter fromBundleImporter;
|
||||
|
||||
@Inject
|
||||
public RepositoryImportResource(RepositoryManager manager,
|
||||
RepositoryDtoToRepositoryMapper mapper,
|
||||
RepositoryServiceFactory serviceFactory,
|
||||
public RepositoryImportResource(RepositoryDtoToRepositoryMapper mapper,
|
||||
ResourceLinks resourceLinks,
|
||||
ScmEventBus eventBus,
|
||||
FullScmRepositoryImporter fullScmRepositoryImporter,
|
||||
RepositoryImportExportEncryption repositoryImportExportEncryption) {
|
||||
this.manager = manager;
|
||||
RepositoryImportDtoToRepositoryImportParametersMapper importParametersMapper,
|
||||
RepositoryImportExportEncryption repositoryImportExportEncryption, FromUrlImporter fromUrlImporter,
|
||||
FromBundleImporter fromBundleImporter) {
|
||||
this.mapper = mapper;
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.resourceLinks = resourceLinks;
|
||||
this.eventBus = eventBus;
|
||||
this.fullScmRepositoryImporter = fullScmRepositoryImporter;
|
||||
this.repositoryImportExportEncryption = repositoryImportExportEncryption;
|
||||
this.importParametersMapper = importParametersMapper;
|
||||
this.fromUrlImporter = fromUrlImporter;
|
||||
this.fromBundleImporter = fromBundleImporter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,49 +148,13 @@ public class RepositoryImportResource {
|
||||
public Response importFromUrl(@Context UriInfo uriInfo,
|
||||
@Pattern(regexp = "\\w{1,10}") @PathParam("type") String type,
|
||||
@Valid RepositoryImportResource.RepositoryImportFromUrlDto request) {
|
||||
RepositoryPermissions.create().check();
|
||||
|
||||
Type t = type(manager, type);
|
||||
if (!t.getName().equals(request.getType())) {
|
||||
if (!type.equals(request.getType())) {
|
||||
throw new WebApplicationException("type of import url and repository does not match", Response.Status.BAD_REQUEST);
|
||||
}
|
||||
checkSupport(t, Command.PULL);
|
||||
|
||||
logger.info("start {} import for external url {}", type, request.getImportUrl());
|
||||
Repository repository = fromUrlImporter.importFromUrl(importParametersMapper.map(request), mapper.map(request));
|
||||
|
||||
Repository repository = mapper.map(request);
|
||||
repository.setPermissions(singletonList(new RepositoryPermission(SecurityUtils.getSubject().getPrincipal().toString(), "OWNER", false)));
|
||||
|
||||
try {
|
||||
repository = manager.create(
|
||||
repository,
|
||||
pullChangesFromRemoteUrl(request)
|
||||
);
|
||||
eventBus.post(new RepositoryImportEvent(HandlerEventType.MODIFY, repository, false));
|
||||
|
||||
return Response.created(URI.create(resourceLinks.repository().self(repository.getNamespace(), repository.getName()))).build();
|
||||
} catch (Exception e) {
|
||||
eventBus.post(new RepositoryImportEvent(HandlerEventType.MODIFY, repository, true));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Consumer<Repository> pullChangesFromRemoteUrl(RepositoryImportFromUrlDto request) {
|
||||
return repository -> {
|
||||
try (RepositoryService service = serviceFactory.create(repository)) {
|
||||
PullCommandBuilder pullCommand = service.getPullCommand();
|
||||
if (!Strings.isNullOrEmpty(request.getUsername()) && !Strings.isNullOrEmpty(request.getPassword())) {
|
||||
pullCommand
|
||||
.withUsername(request.getUsername())
|
||||
.withPassword(request.getPassword());
|
||||
}
|
||||
|
||||
pullCommand.pull(request.getImportUrl());
|
||||
} catch (IOException e) {
|
||||
throw new InternalRepositoryException(repository, "Failed to import from remote url", e);
|
||||
}
|
||||
};
|
||||
return Response.created(URI.create(resourceLinks.repository().self(repository.getNamespace(), repository.getName()))).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,25 +278,13 @@ public class RepositoryImportResource {
|
||||
inputStream = decryptInputStream(inputStream, repositoryDto.getPassword());
|
||||
}
|
||||
|
||||
Type t = type(manager, type);
|
||||
checkSupport(t, Command.UNBUNDLE);
|
||||
if (!type.equals(repositoryDto.getType())) {
|
||||
throw new WebApplicationException("type of import url and repository does not match", Response.Status.BAD_REQUEST);
|
||||
}
|
||||
|
||||
Repository repository = mapper.map(repositoryDto);
|
||||
repository.setPermissions(singletonList(
|
||||
new RepositoryPermission(SecurityUtils.getSubject().getPrincipal().toString(), "OWNER", false)
|
||||
));
|
||||
|
||||
try {
|
||||
repository = manager.create(
|
||||
repository,
|
||||
unbundleImport(inputStream, compressed)
|
||||
);
|
||||
eventBus.post(new RepositoryImportEvent(HandlerEventType.MODIFY, repository, false));
|
||||
|
||||
} catch (Exception e) {
|
||||
eventBus.post(new RepositoryImportEvent(HandlerEventType.MODIFY, repository, true));
|
||||
throw e;
|
||||
}
|
||||
repository = fromBundleImporter.importFromBundle(compressed, inputStream, repository);
|
||||
|
||||
return repository;
|
||||
}
|
||||
@@ -363,27 +297,6 @@ public class RepositoryImportResource {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Consumer<Repository> unbundleImport(InputStream inputStream, boolean compressed) {
|
||||
return repository -> {
|
||||
File file = null;
|
||||
try (RepositoryService service = serviceFactory.create(repository)) {
|
||||
file = File.createTempFile("scm-import-", ".bundle");
|
||||
long length = Files.asByteSink(file).writeFrom(inputStream);
|
||||
logger.info("copied {} bytes to temp, start bundle import", length);
|
||||
service.getUnbundleCommand().setCompressed(compressed).unbundle(file);
|
||||
} catch (IOException e) {
|
||||
throw new InternalRepositoryException(repository, "Failed to import from bundle", e);
|
||||
} finally {
|
||||
try {
|
||||
IOUtil.delete(file);
|
||||
} catch (IOException ex) {
|
||||
logger.warn("could not delete temporary file", ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private RepositoryImportFromFileDto extractRepositoryDto(Map<String, List<InputPart>> formParts) {
|
||||
RepositoryImportFromFileDto repositoryDto = extractFromInputPart(formParts.get("repository"), RepositoryImportFromFileDto.class);
|
||||
checkNotNull(repositoryDto, "repository data is required");
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.importexport;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.io.Files;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryImportEvent;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.util.IOUtil;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static sonia.scm.importexport.RepositoryTypeSupportChecker.checkSupport;
|
||||
import static sonia.scm.importexport.RepositoryTypeSupportChecker.type;
|
||||
|
||||
public class FromBundleImporter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FromBundleImporter.class);
|
||||
|
||||
private final RepositoryManager manager;
|
||||
private final RepositoryServiceFactory serviceFactory;
|
||||
private final ScmEventBus eventBus;
|
||||
|
||||
@Inject
|
||||
public FromBundleImporter(RepositoryManager manager, RepositoryServiceFactory serviceFactory, ScmEventBus eventBus) {
|
||||
this.manager = manager;
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
public Repository importFromBundle(boolean compressed, InputStream inputStream, Repository repository) {
|
||||
Type t = type(manager, repository.getType());
|
||||
checkSupport(t, Command.UNBUNDLE);
|
||||
|
||||
repository.setPermissions(singletonList(
|
||||
new RepositoryPermission(SecurityUtils.getSubject().getPrincipal().toString(), "OWNER", false)
|
||||
));
|
||||
|
||||
try {
|
||||
repository = manager.create(repository, unbundleImport(inputStream, compressed));
|
||||
eventBus.post(new RepositoryImportEvent(HandlerEventType.MODIFY, repository, false));
|
||||
} catch (Exception e) {
|
||||
eventBus.post(new RepositoryImportEvent(HandlerEventType.MODIFY, repository, true));
|
||||
throw e;
|
||||
}
|
||||
|
||||
return repository;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Consumer<Repository> unbundleImport(InputStream inputStream, boolean compressed) {
|
||||
return repository -> {
|
||||
File file = null;
|
||||
try (RepositoryService service = serviceFactory.create(repository)) {
|
||||
file = File.createTempFile("scm-import-", ".bundle");
|
||||
long length = Files.asByteSink(file).writeFrom(inputStream);
|
||||
LOG.info("copied {} bytes to temp, start bundle import", length);
|
||||
service.getUnbundleCommand().setCompressed(compressed).unbundle(file);
|
||||
} catch (IOException e) {
|
||||
throw new InternalRepositoryException(repository, "Failed to import from bundle", e);
|
||||
} finally {
|
||||
try {
|
||||
IOUtil.delete(file);
|
||||
} catch (IOException ex) {
|
||||
LOG.warn("could not delete temporary file", ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.importexport;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.HandlerEventType;
|
||||
import sonia.scm.Type;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryImportEvent;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.repository.api.PullCommandBuilder;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static sonia.scm.importexport.RepositoryTypeSupportChecker.checkSupport;
|
||||
import static sonia.scm.importexport.RepositoryTypeSupportChecker.type;
|
||||
|
||||
public class FromUrlImporter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FromUrlImporter.class);
|
||||
|
||||
private final RepositoryManager manager;
|
||||
private final RepositoryServiceFactory serviceFactory;
|
||||
private final ScmEventBus eventBus;
|
||||
|
||||
@Inject
|
||||
public FromUrlImporter(RepositoryManager manager, RepositoryServiceFactory serviceFactory, ScmEventBus eventBus) {
|
||||
this.manager = manager;
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
public Repository importFromUrl(RepositoryImportParameters parameters, Repository repository) {
|
||||
Type t = type(manager, repository.getType());
|
||||
RepositoryPermissions.create().check();
|
||||
checkSupport(t, Command.PULL);
|
||||
|
||||
LOG.info("start {} import for external url {}", repository.getType(), parameters.getImportUrl());
|
||||
|
||||
repository.setPermissions(singletonList(new RepositoryPermission(SecurityUtils.getSubject().getPrincipal().toString(), "OWNER", false)));
|
||||
|
||||
try {
|
||||
repository = manager.create(
|
||||
repository,
|
||||
pullChangesFromRemoteUrl(parameters)
|
||||
);
|
||||
eventBus.post(new RepositoryImportEvent(HandlerEventType.MODIFY, repository, false));
|
||||
} catch (Exception e) {
|
||||
eventBus.post(new RepositoryImportEvent(HandlerEventType.MODIFY, repository, true));
|
||||
throw e;
|
||||
}
|
||||
return repository;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Consumer<Repository> pullChangesFromRemoteUrl(RepositoryImportParameters parameters) {
|
||||
return repository -> {
|
||||
try (RepositoryService service = serviceFactory.create(repository)) {
|
||||
PullCommandBuilder pullCommand = service.getPullCommand();
|
||||
if (!Strings.isNullOrEmpty(parameters.getUsername()) && !Strings.isNullOrEmpty(parameters.getPassword())) {
|
||||
pullCommand
|
||||
.withUsername(parameters.getUsername())
|
||||
.withPassword(parameters.getPassword());
|
||||
}
|
||||
|
||||
pullCommand.pull(parameters.getImportUrl());
|
||||
} catch (IOException e) {
|
||||
throw new InternalRepositoryException(repository, "Failed to import from remote url", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class RepositoryImportParameters {
|
||||
private String importUrl;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
package sonia.scm.importexport;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -36,7 +36,7 @@ import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.Set;
|
||||
|
||||
class RepositoryTypeSupportChecker {
|
||||
public class RepositoryTypeSupportChecker {
|
||||
|
||||
private RepositoryTypeSupportChecker() {
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class RepositoryTypeSupportChecker {
|
||||
* @param type repository type
|
||||
* @param cmd command
|
||||
*/
|
||||
static void checkSupport(Type type, Command cmd) {
|
||||
public static void checkSupport(Type type, Command cmd) {
|
||||
if (!(type instanceof RepositoryType)) {
|
||||
logger.warn("type {} is not a repository type", type.getName());
|
||||
throw new WebApplicationException(Response.Status.BAD_REQUEST);
|
||||
@@ -65,7 +65,7 @@ class RepositoryTypeSupportChecker {
|
||||
}
|
||||
|
||||
@SuppressWarnings("javasecurity:S5145") // the type parameter is validated in the resource to only contain valid characters (\w)
|
||||
static Type type(RepositoryManager manager, String type) {
|
||||
public static Type type(RepositoryManager manager, String type) {
|
||||
RepositoryHandler handler = manager.getHandler(type);
|
||||
if (handler == null) {
|
||||
logger.warn("no handler for type {} found", type);
|
||||
@@ -48,6 +48,8 @@ import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.importexport.ExportFileExtensionResolver;
|
||||
import sonia.scm.importexport.ExportService;
|
||||
import sonia.scm.importexport.ExportStatus;
|
||||
import sonia.scm.importexport.FromBundleImporter;
|
||||
import sonia.scm.importexport.FromUrlImporter;
|
||||
import sonia.scm.importexport.FullScmRepositoryExporter;
|
||||
import sonia.scm.importexport.FullScmRepositoryImporter;
|
||||
import sonia.scm.importexport.RepositoryImportExportEncryption;
|
||||
@@ -64,11 +66,8 @@ import sonia.scm.repository.RepositoryType;
|
||||
import sonia.scm.repository.api.BundleCommandBuilder;
|
||||
import sonia.scm.repository.api.Command;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
import sonia.scm.repository.api.PullCommandBuilder;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.repository.api.UnbundleCommandBuilder;
|
||||
import sonia.scm.repository.api.UnbundleResponse;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.web.RestDispatcher;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
@@ -77,7 +76,6 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -92,7 +90,6 @@ import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
@@ -107,13 +104,10 @@ import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.RETURNS_SELF;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -166,6 +160,10 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
@Mock
|
||||
private RepositoryImportExportEncryption repositoryImportExportEncryption;
|
||||
@Mock
|
||||
private FromUrlImporter fromUrlImporter;
|
||||
@Mock
|
||||
private FromBundleImporter fromBundleImporter;
|
||||
@Mock
|
||||
private ExportFileExtensionResolver fileExtensionResolver;
|
||||
@Mock
|
||||
private ExportService exportService;
|
||||
@@ -175,7 +173,6 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
|
||||
private final URI baseUri = URI.create("/");
|
||||
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||
private Repository repositoryMarkedAsExported;
|
||||
|
||||
@InjectMocks
|
||||
private RepositoryToRepositoryDtoMapperImpl repositoryToDtoMapper;
|
||||
@@ -190,7 +187,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
super.manager = repositoryManager;
|
||||
RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks);
|
||||
super.repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks, repositoryInitializer);
|
||||
super.repositoryImportResource = new RepositoryImportResource(repositoryManager, dtoToRepositoryMapper, serviceFactory, resourceLinks, eventBus, fullScmRepositoryImporter, repositoryImportExportEncryption);
|
||||
super.repositoryImportResource = new RepositoryImportResource(dtoToRepositoryMapper, resourceLinks, fullScmRepositoryImporter, new RepositoryImportDtoToRepositoryImportParametersMapperImpl(), repositoryImportExportEncryption, fromUrlImporter, fromBundleImporter);
|
||||
super.repositoryExportResource = new RepositoryExportResource(repositoryManager, serviceFactory, fullScmRepositoryExporter, repositoryImportExportEncryption, exportService, exportInformationToDtoMapper, fileExtensionResolver, resourceLinks);
|
||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||
@@ -551,88 +548,6 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
assertThat(captor.getValue().isFailed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPullChangesFromRemoteUrl() throws IOException {
|
||||
PullCommandBuilder pullCommandBuilder = mock(PullCommandBuilder.class, RETURNS_SELF);
|
||||
when(service.getPullCommand()).thenReturn(pullCommandBuilder);
|
||||
|
||||
Repository repository = RepositoryTestData.createHeartOfGold();
|
||||
RepositoryImportResource.RepositoryImportFromUrlDto repositoryImportFromUrlDto = new RepositoryImportResource.RepositoryImportFromUrlDto();
|
||||
repositoryImportFromUrlDto.setImportUrl("https://scm-manager.org/scm/repo/scmadmin/scm-manager.git");
|
||||
repositoryImportFromUrlDto.setNamespace("scmadmin");
|
||||
repositoryImportFromUrlDto.setName("scm-manager");
|
||||
|
||||
Consumer<Repository> repositoryConsumer = repositoryImportResource.pullChangesFromRemoteUrl(repositoryImportFromUrlDto);
|
||||
repositoryConsumer.accept(repository);
|
||||
|
||||
verify(pullCommandBuilder).pull("https://scm-manager.org/scm/repo/scmadmin/scm-manager.git");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPullChangesFromRemoteUrlWithCredentials() {
|
||||
PullCommandBuilder pullCommandBuilder = mock(PullCommandBuilder.class, RETURNS_SELF);
|
||||
when(service.getPullCommand()).thenReturn(pullCommandBuilder);
|
||||
|
||||
Repository repository = RepositoryTestData.createHeartOfGold();
|
||||
RepositoryImportResource.RepositoryImportFromUrlDto repositoryImportFromUrlDto = new RepositoryImportResource.RepositoryImportFromUrlDto();
|
||||
repositoryImportFromUrlDto.setImportUrl("https://scm-manager.org/scm/repo/scmadmin/scm-manager.git");
|
||||
repositoryImportFromUrlDto.setNamespace("scmadmin");
|
||||
repositoryImportFromUrlDto.setName("scm-manager");
|
||||
repositoryImportFromUrlDto.setUsername("trillian");
|
||||
repositoryImportFromUrlDto.setPassword("secret");
|
||||
|
||||
Consumer<Repository> repositoryConsumer = repositoryImportResource.pullChangesFromRemoteUrl(repositoryImportFromUrlDto);
|
||||
repositoryConsumer.accept(repository);
|
||||
|
||||
verify(pullCommandBuilder).withUsername("trillian");
|
||||
verify(pullCommandBuilder).withPassword("secret");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowImportFailedEvent() throws IOException {
|
||||
PullCommandBuilder pullCommandBuilder = mock(PullCommandBuilder.class, RETURNS_SELF);
|
||||
when(service.getPullCommand()).thenReturn(pullCommandBuilder);
|
||||
doThrow(ImportFailedException.class).when(pullCommandBuilder).pull(anyString());
|
||||
|
||||
Repository repository = RepositoryTestData.createHeartOfGold();
|
||||
RepositoryImportResource.RepositoryImportFromUrlDto repositoryImportFromUrlDto = new RepositoryImportResource.RepositoryImportFromUrlDto();
|
||||
repositoryImportFromUrlDto.setImportUrl("https://scm-manager.org/scm/repo/scmadmin/scm-manager.git");
|
||||
repositoryImportFromUrlDto.setNamespace("scmadmin");
|
||||
repositoryImportFromUrlDto.setName("scm-manager");
|
||||
|
||||
Consumer<Repository> repositoryConsumer = repositoryImportResource.pullChangesFromRemoteUrl(repositoryImportFromUrlDto);
|
||||
assertThrows(ImportFailedException.class, () -> repositoryConsumer.accept(repository));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldImportRepositoryFromBundle() throws IOException, URISyntaxException {
|
||||
when(manager.getHandler("svn")).thenReturn(repositoryHandler);
|
||||
when(repositoryHandler.getType()).thenReturn(new RepositoryType("svn", "svn", ImmutableSet.of(Command.UNBUNDLE)));
|
||||
when(repositoryManager.create(any(), any())).thenReturn(RepositoryTestData.createHeartOfGold());
|
||||
|
||||
RepositoryDto repositoryDto = new RepositoryDto();
|
||||
repositoryDto.setName("HeartOfGold");
|
||||
repositoryDto.setNamespace("hitchhiker");
|
||||
repositoryDto.setType("svn");
|
||||
|
||||
URL dumpUrl = Resources.getResource("sonia/scm/api/v2/svn.dump");
|
||||
byte[] svnDump = Resources.toByteArray(dumpUrl);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "import/svn/bundle");
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
multipartRequest(request, Collections.singletonMap("bundle", new ByteArrayInputStream(svnDump)), repositoryDto);
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertEquals(HttpServletResponse.SC_CREATED, response.getStatus());
|
||||
assertEquals("/v2/repositories/hitchhiker/HeartOfGold", response.getOutputHeaders().get("Location").get(0).toString());
|
||||
ArgumentCaptor<RepositoryImportEvent> event = ArgumentCaptor.forClass(RepositoryImportEvent.class);
|
||||
verify(eventBus).post(event.capture());
|
||||
assertFalse(event.getValue().isFailed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowFailedEventOnImportRepositoryFromBundle() throws IOException, URISyntaxException {
|
||||
when(manager.getHandler("svn")).thenReturn(repositoryHandler);
|
||||
@@ -661,44 +576,6 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
||||
assertTrue(event.getValue().isFailed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldImportCompressedBundle() throws IOException {
|
||||
URL dumpUrl = Resources.getResource("sonia/scm/api/v2/svn.dump.gz");
|
||||
byte[] svnDump = Resources.toByteArray(dumpUrl);
|
||||
|
||||
UnbundleCommandBuilder ubc = mock(UnbundleCommandBuilder.class, RETURNS_SELF);
|
||||
when(ubc.unbundle(any(File.class))).thenReturn(new UnbundleResponse(42));
|
||||
RepositoryService service = mock(RepositoryService.class);
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||
when(service.getUnbundleCommand()).thenReturn(ubc);
|
||||
InputStream in = new ByteArrayInputStream(svnDump);
|
||||
|
||||
Consumer<Repository> repositoryConsumer = repositoryImportResource.unbundleImport(in, true);
|
||||
repositoryConsumer.accept(RepositoryTestData.createHeartOfGold("svn"));
|
||||
|
||||
verify(ubc).setCompressed(true);
|
||||
verify(ubc).unbundle(any(File.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldImportNonCompressedBundle() throws IOException {
|
||||
URL dumpUrl = Resources.getResource("sonia/scm/api/v2/svn.dump");
|
||||
byte[] svnDump = Resources.toByteArray(dumpUrl);
|
||||
|
||||
UnbundleCommandBuilder ubc = mock(UnbundleCommandBuilder.class, RETURNS_SELF);
|
||||
when(ubc.unbundle(any(File.class))).thenReturn(new UnbundleResponse(21));
|
||||
RepositoryService service = mock(RepositoryService.class);
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||
when(service.getUnbundleCommand()).thenReturn(ubc);
|
||||
InputStream in = new ByteArrayInputStream(svnDump);
|
||||
|
||||
Consumer<Repository> repositoryConsumer = repositoryImportResource.unbundleImport(in, false);
|
||||
repositoryConsumer.accept(RepositoryTestData.createHeartOfGold("svn"));
|
||||
|
||||
verify(ubc, never()).setCompressed(true);
|
||||
verify(ubc).unbundle(any(File.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMarkRepositoryAsArchived() throws Exception {
|
||||
String namespace = "space";
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.importexport;
|
||||
|
||||
import com.google.common.io.Resources;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryTestData;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.repository.api.UnbundleCommandBuilder;
|
||||
import sonia.scm.repository.api.UnbundleResponse;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.RETURNS_SELF;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
class FromBundleImporterTest {
|
||||
|
||||
@Mock
|
||||
private RepositoryManager manager;
|
||||
@Mock
|
||||
private RepositoryServiceFactory serviceFactory;
|
||||
@Mock
|
||||
private ScmEventBus eventBus;
|
||||
|
||||
@InjectMocks
|
||||
private FromBundleImporter importer;
|
||||
|
||||
@Test
|
||||
void shouldImportCompressedBundle() throws IOException {
|
||||
URL dumpUrl = Resources.getResource("sonia/scm/api/v2/svn.dump.gz");
|
||||
byte[] svnDump = Resources.toByteArray(dumpUrl);
|
||||
|
||||
UnbundleCommandBuilder ubc = mock(UnbundleCommandBuilder.class, RETURNS_SELF);
|
||||
when(ubc.unbundle(any(File.class))).thenReturn(new UnbundleResponse(42));
|
||||
RepositoryService service = mock(RepositoryService.class);
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||
when(service.getUnbundleCommand()).thenReturn(ubc);
|
||||
InputStream in = new ByteArrayInputStream(svnDump);
|
||||
|
||||
Consumer<Repository> repositoryConsumer = importer.unbundleImport(in, true);
|
||||
repositoryConsumer.accept(RepositoryTestData.createHeartOfGold("svn"));
|
||||
|
||||
verify(ubc).setCompressed(true);
|
||||
verify(ubc).unbundle(any(File.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldImportNonCompressedBundle() throws IOException {
|
||||
URL dumpUrl = Resources.getResource("sonia/scm/api/v2/svn.dump");
|
||||
byte[] svnDump = Resources.toByteArray(dumpUrl);
|
||||
|
||||
UnbundleCommandBuilder ubc = mock(UnbundleCommandBuilder.class, RETURNS_SELF);
|
||||
when(ubc.unbundle(any(File.class))).thenReturn(new UnbundleResponse(21));
|
||||
RepositoryService service = mock(RepositoryService.class);
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||
when(service.getUnbundleCommand()).thenReturn(ubc);
|
||||
InputStream in = new ByteArrayInputStream(svnDump);
|
||||
|
||||
Consumer<Repository> repositoryConsumer = importer.unbundleImport(in, false);
|
||||
repositoryConsumer.accept(RepositoryTestData.createHeartOfGold("svn"));
|
||||
|
||||
verify(ubc, never()).setCompressed(true);
|
||||
verify(ubc).unbundle(any(File.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.importexport;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryTestData;
|
||||
import sonia.scm.repository.api.ImportFailedException;
|
||||
import sonia.scm.repository.api.PullCommandBuilder;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.RETURNS_SELF;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FromUrlImporterTest {
|
||||
|
||||
@Mock
|
||||
private RepositoryManager manager;
|
||||
@Mock
|
||||
private RepositoryServiceFactory serviceFactory;
|
||||
@Mock
|
||||
private RepositoryService service;
|
||||
@Mock
|
||||
private ScmEventBus eventBus;
|
||||
|
||||
@InjectMocks
|
||||
private FromUrlImporter importer;
|
||||
|
||||
@BeforeEach
|
||||
void setUpMocks() {
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPullChangesFromRemoteUrl() throws IOException {
|
||||
PullCommandBuilder pullCommandBuilder = mock(PullCommandBuilder.class, RETURNS_SELF);
|
||||
when(service.getPullCommand()).thenReturn(pullCommandBuilder);
|
||||
|
||||
Repository repository = RepositoryTestData.createHeartOfGold();
|
||||
FromUrlImporter.RepositoryImportParameters parameters = new FromUrlImporter.RepositoryImportParameters();
|
||||
parameters.setImportUrl("https://scm-manager.org/scm/repo/scmadmin/scm-manager.git");
|
||||
|
||||
Consumer<Repository> repositoryConsumer = importer.pullChangesFromRemoteUrl(parameters);
|
||||
repositoryConsumer.accept(repository);
|
||||
|
||||
verify(pullCommandBuilder).pull("https://scm-manager.org/scm/repo/scmadmin/scm-manager.git");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPullChangesFromRemoteUrlWithCredentials() {
|
||||
PullCommandBuilder pullCommandBuilder = mock(PullCommandBuilder.class, RETURNS_SELF);
|
||||
when(service.getPullCommand()).thenReturn(pullCommandBuilder);
|
||||
|
||||
Repository repository = RepositoryTestData.createHeartOfGold();
|
||||
FromUrlImporter.RepositoryImportParameters parameters = new FromUrlImporter.RepositoryImportParameters();
|
||||
parameters.setImportUrl("https://scm-manager.org/scm/repo/scmadmin/scm-manager.git");
|
||||
parameters.setUsername("trillian");
|
||||
parameters.setPassword("secret");
|
||||
|
||||
Consumer<Repository> repositoryConsumer = importer.pullChangesFromRemoteUrl(parameters);
|
||||
repositoryConsumer.accept(repository);
|
||||
|
||||
verify(pullCommandBuilder).withUsername("trillian");
|
||||
verify(pullCommandBuilder).withPassword("secret");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowImportFailedEvent() throws IOException {
|
||||
PullCommandBuilder pullCommandBuilder = mock(PullCommandBuilder.class, RETURNS_SELF);
|
||||
when(service.getPullCommand()).thenReturn(pullCommandBuilder);
|
||||
doThrow(ImportFailedException.class).when(pullCommandBuilder).pull(anyString());
|
||||
|
||||
Repository repository = RepositoryTestData.createHeartOfGold();
|
||||
FromUrlImporter.RepositoryImportParameters parameters = new FromUrlImporter.RepositoryImportParameters();
|
||||
parameters.setImportUrl("https://scm-manager.org/scm/repo/scmadmin/scm-manager.git");
|
||||
|
||||
Consumer<Repository> repositoryConsumer = importer.pullChangesFromRemoteUrl(parameters);
|
||||
assertThrows(ImportFailedException.class, () -> repositoryConsumer.accept(repository));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user