mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-03-06 12:20:56 +01:00
Make modify command available
This commit is contained in:
@@ -15,6 +15,29 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Use this {@link ModifyCommandBuilder} to make file changes to the head of a branch. You can
|
||||
* <ul>
|
||||
* <li>create new files ({@link #createFile(String)}</li>
|
||||
* <li>modify existing files ({@link #modifyFile(String)}</li>
|
||||
* <li>delete existing files ({@link #deleteFile(String)}</li>
|
||||
* <li>move/rename existing files ({@link #moveFile(String, String)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* You can collect multiple changes before they are executed with a call to {@link #execute()}.
|
||||
*
|
||||
* <p>Example:
|
||||
* <pre>
|
||||
* commandBuilder
|
||||
* .setBranch("feature/branch")
|
||||
* .setCommitMessage("make some changes")
|
||||
* .setAuthor(new Person())
|
||||
* .createFile("file/to/create").withData(inputStream)
|
||||
* .deleteFile("old/file/to/delete")
|
||||
* .execute();
|
||||
* </pre>
|
||||
* </p>
|
||||
*/
|
||||
public class ModifyCommandBuilder {
|
||||
|
||||
private final ModifyCommand command;
|
||||
@@ -27,37 +50,127 @@ public class ModifyCommandBuilder {
|
||||
this.workdir = workdirProvider.createNewWorkdir();
|
||||
}
|
||||
|
||||
ModifyCommandBuilder setBranchToModify(String branchToModify) {
|
||||
/**
|
||||
* Set the branch that should be modified. The new commit will be made for this branch.
|
||||
* @param branchToModify The branch to modify.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public ModifyCommandBuilder setBranchToModify(String branchToModify) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ContentLoader createFile(String path) {
|
||||
/**
|
||||
* Create a new file. The content of the file will be specified in a subsequent call to
|
||||
* {@link ContentLoader#withData(ByteSource)} or {@link ContentLoader#withData(InputStream)}.
|
||||
* @param path The path and the name of the file that should be created.
|
||||
* @return The loader to specify the content of the new file.
|
||||
*/
|
||||
public ContentLoader createFile(String path) {
|
||||
return new ContentLoader(
|
||||
content -> request.addRequest(new ModifyCommandRequest.CreateFileRequest(path, content))
|
||||
);
|
||||
}
|
||||
|
||||
ContentLoader modifyFile(String path) {
|
||||
/**
|
||||
* Modify an existing file. The new content of the file will be specified in a subsequent call to
|
||||
* {@link ContentLoader#withData(ByteSource)} or {@link ContentLoader#withData(InputStream)}.
|
||||
* @param path The path and the name of the file that should be modified.
|
||||
* @return The loader to specify the new content of the file.
|
||||
*/
|
||||
public ContentLoader modifyFile(String path) {
|
||||
return new ContentLoader(
|
||||
content -> request.addRequest(new ModifyCommandRequest.ModifyFileRequest(path, content))
|
||||
);
|
||||
}
|
||||
|
||||
ModifyCommandBuilder deleteFile(String path) {
|
||||
/**
|
||||
* Delete an existing file.
|
||||
* @param path The path and the name of the file that should be deleted.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public ModifyCommandBuilder deleteFile(String path) {
|
||||
request.addRequest(new ModifyCommandRequest.DeleteFileRequest(path));
|
||||
return this;
|
||||
}
|
||||
|
||||
ModifyCommandBuilder moveFile(String sourcePath, String targetPath) {
|
||||
/**
|
||||
* Move an existing file.
|
||||
* @param sourcePath The path and the name of the file that should be moved.
|
||||
* @param targetPath The new path and name the file should be moved to.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public ModifyCommandBuilder moveFile(String sourcePath, String targetPath) {
|
||||
request.addRequest(new ModifyCommandRequest.MoveFileRequest(sourcePath, targetPath));
|
||||
return this;
|
||||
}
|
||||
|
||||
String execute() {
|
||||
/**
|
||||
* Apply the changes and create a new commit with the given message and author.
|
||||
* @return The revision of the new commit.
|
||||
*/
|
||||
public String execute() {
|
||||
Preconditions.checkArgument(request.isValid(), "commit message, author and branch are required");
|
||||
return command.execute(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the commit message for the new commit.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public ModifyCommandBuilder setCommitMessage(String message) {
|
||||
request.setCommitMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the author for the new commit.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public ModifyCommandBuilder setAuthor(Person author) {
|
||||
request.setAuthor(author);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the branch the changes should be made upon.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public ModifyCommandBuilder setBranch(String branch) {
|
||||
request.setBranch(branch);
|
||||
return this;
|
||||
}
|
||||
|
||||
public class ContentLoader {
|
||||
|
||||
private final Consumer<File> contentConsumer;
|
||||
|
||||
private ContentLoader(Consumer<File> contentConsumer) {
|
||||
this.contentConsumer = contentConsumer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the data of the file using a {@link ByteSource}.
|
||||
* @return The builder instance.
|
||||
* @throws IOException If the data could not be read.
|
||||
*/
|
||||
public ModifyCommandBuilder withData(ByteSource data) throws IOException {
|
||||
File content = loadData(data);
|
||||
contentConsumer.accept(content);
|
||||
return ModifyCommandBuilder.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the data of the file using an {@link InputStream}.
|
||||
* @return The builder instance.
|
||||
* @throws IOException If the data could not be read.
|
||||
*/
|
||||
public ModifyCommandBuilder withData(InputStream data) throws IOException {
|
||||
File content = loadData(data);
|
||||
contentConsumer.accept(content);
|
||||
return ModifyCommandBuilder.this;
|
||||
}
|
||||
}
|
||||
|
||||
private File loadData(ByteSource data) throws IOException {
|
||||
File file = createTemporaryFile();
|
||||
data.copyTo(Files.asByteSink(file));
|
||||
@@ -75,39 +188,4 @@ public class ModifyCommandBuilder {
|
||||
private File createTemporaryFile() throws IOException {
|
||||
return File.createTempFile("upload-", "", workdir);
|
||||
}
|
||||
|
||||
public ModifyCommandBuilder setCommitMessage(String message) {
|
||||
request.setCommitMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModifyCommandBuilder setAuthor(Person author) {
|
||||
request.setAuthor(author);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModifyCommandBuilder setBranch(String branch) {
|
||||
request.setBranch(branch);
|
||||
return this;
|
||||
}
|
||||
|
||||
public class ContentLoader {
|
||||
|
||||
private final Consumer<File> contentConsumer;
|
||||
|
||||
private ContentLoader(Consumer<File> contentConsumer) {
|
||||
this.contentConsumer = contentConsumer;
|
||||
}
|
||||
|
||||
public ModifyCommandBuilder withData(ByteSource data) throws IOException {
|
||||
File content = loadData(data);
|
||||
contentConsumer.accept(content);
|
||||
return ModifyCommandBuilder.this;
|
||||
}
|
||||
public ModifyCommandBuilder withData(InputStream data) throws IOException {
|
||||
File content = loadData(data);
|
||||
contentConsumer.accept(content);
|
||||
return ModifyCommandBuilder.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import sonia.scm.repository.PreProcessorUtil;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.repository.spi.RepositoryServiceProvider;
|
||||
import sonia.scm.repository.util.WorkdirProvider;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
@@ -91,22 +92,25 @@ public final class RepositoryService implements Closeable {
|
||||
private final RepositoryServiceProvider provider;
|
||||
private final Repository repository;
|
||||
private final Set<ScmProtocolProvider> protocolProviders;
|
||||
private final WorkdirProvider workdirProvider;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link RepositoryService}. This constructor should only
|
||||
* be called from the {@link RepositoryServiceFactory}.
|
||||
* @param cacheManager cache manager
|
||||
* @param cacheManager cache manager
|
||||
* @param provider implementation for {@link RepositoryServiceProvider}
|
||||
* @param repository the repository
|
||||
* @param workdirProvider
|
||||
*/
|
||||
RepositoryService(CacheManager cacheManager,
|
||||
RepositoryServiceProvider provider, Repository repository,
|
||||
PreProcessorUtil preProcessorUtil, Set<ScmProtocolProvider> protocolProviders) {
|
||||
RepositoryServiceProvider provider, Repository repository,
|
||||
PreProcessorUtil preProcessorUtil, Set<ScmProtocolProvider> protocolProviders, WorkdirProvider workdirProvider) {
|
||||
this.cacheManager = cacheManager;
|
||||
this.provider = provider;
|
||||
this.repository = repository;
|
||||
this.preProcessorUtil = preProcessorUtil;
|
||||
this.protocolProviders = protocolProviders;
|
||||
this.workdirProvider = workdirProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,6 +403,27 @@ public final class RepositoryService implements Closeable {
|
||||
return new MergeCommandBuilder(provider.getMergeCommand());
|
||||
}
|
||||
|
||||
/**
|
||||
* The modify command makes changes to the head of a branch. It is possible to
|
||||
* <ul>
|
||||
* <li>create new files</li>
|
||||
* <li>delete existing files</li>
|
||||
* <li>modify/replace files</li>
|
||||
* <li>move files</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return instance of {@link ModifyCommandBuilder}
|
||||
* @throws CommandNotSupportedException if the command is not supported
|
||||
* by the implementation of the repository service provider.
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public ModifyCommandBuilder getModifyCommand() {
|
||||
LOG.debug("create modify command for repository {}",
|
||||
repository.getNamespaceAndName());
|
||||
|
||||
return new ModifyCommandBuilder(provider.getModifyCommand(), workdirProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the command is supported by the repository service.
|
||||
*
|
||||
|
||||
@@ -61,6 +61,7 @@ import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.repository.spi.RepositoryServiceProvider;
|
||||
import sonia.scm.repository.spi.RepositoryServiceResolver;
|
||||
import sonia.scm.repository.util.WorkdirProvider;
|
||||
import sonia.scm.security.ScmSecurityException;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -256,7 +257,7 @@ public final class RepositoryServiceFactory
|
||||
}
|
||||
|
||||
service = new RepositoryService(cacheManager, provider, repository,
|
||||
preProcessorUtil, protocolProviders);
|
||||
preProcessorUtil, protocolProviders, workdirProvider);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -373,4 +374,6 @@ public final class RepositoryServiceFactory
|
||||
private final Set<RepositoryServiceResolver> resolvers;
|
||||
|
||||
private Set<ScmProtocolProvider> protocolProviders;
|
||||
|
||||
private WorkdirProvider workdirProvider;
|
||||
}
|
||||
|
||||
@@ -275,4 +275,12 @@ public abstract class RepositoryServiceProvider implements Closeable
|
||||
{
|
||||
throw new CommandNotSupportedException(Command.MERGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public ModifyCommand getModifyCommand()
|
||||
{
|
||||
throw new CommandNotSupportedException(Command.MODIFY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class RepositoryServiceTest {
|
||||
|
||||
@Test
|
||||
public void shouldReturnMatchingProtocolsFromProvider() {
|
||||
RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()));
|
||||
RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null);
|
||||
Stream<ScmProtocol> supportedProtocols = repositoryService.getSupportedProtocols();
|
||||
|
||||
assertThat(sizeOf(supportedProtocols.collect(Collectors.toList()))).isEqualTo(1);
|
||||
@@ -32,7 +32,7 @@ public class RepositoryServiceTest {
|
||||
|
||||
@Test
|
||||
public void shouldFindKnownProtocol() {
|
||||
RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()));
|
||||
RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null);
|
||||
|
||||
HttpScmProtocol protocol = repositoryService.getProtocol(HttpScmProtocol.class);
|
||||
|
||||
@@ -41,7 +41,7 @@ public class RepositoryServiceTest {
|
||||
|
||||
@Test
|
||||
public void shouldFailForUnknownProtocol() {
|
||||
RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()));
|
||||
RepositoryService repositoryService = new RepositoryService(null, provider, repository, null, Collections.singleton(new DummyScmProtocolProvider()), null);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
repositoryService.getProtocol(UnknownScmProtocol.class);
|
||||
|
||||
Reference in New Issue
Block a user