Implement first steps for merge

This commit is contained in:
René Pfeuffer
2018-11-06 17:14:27 +01:00
parent e0cc99a3d8
commit 6863337faf
8 changed files with 211 additions and 2 deletions

View File

@@ -0,0 +1,25 @@
package sonia.scm.repository;
import java.util.function.Consumer;
public class CloseableWrapper<C> implements AutoCloseable {
private final C wrapped;
private final Consumer<C> cleanup;
public CloseableWrapper(C wrapped, Consumer<C> cleanup) {
this.wrapped = wrapped;
this.cleanup = cleanup;
}
public C get() { return wrapped; }
@Override
public void close() {
try {
cleanup.accept(wrapped);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
}

View File

@@ -91,6 +91,8 @@ public class GitRepositoryHandler
private final Scheduler scheduler;
private final GitWorkdirPool workdirPool;
private Task task;
//~--- constructors ---------------------------------------------------------
@@ -104,10 +106,11 @@ public class GitRepositoryHandler
* @param scheduler
*/
@Inject
public GitRepositoryHandler(ConfigurationStoreFactory storeFactory, FileSystem fileSystem, Scheduler scheduler)
public GitRepositoryHandler(ConfigurationStoreFactory storeFactory, FileSystem fileSystem, Scheduler scheduler, GitWorkdirPool workdirPool)
{
super(storeFactory, fileSystem);
this.scheduler = scheduler;
this.workdirPool = workdirPool;
}
//~--- get methods ----------------------------------------------------------
@@ -235,4 +238,8 @@ public class GitRepositoryHandler
{
return new File(directory, DIRECTORY_REFS).exists();
}
public GitWorkdirPool getWorkdirPool() {
return workdirPool;
}
}

View File

@@ -0,0 +1,46 @@
package sonia.scm.repository;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import java.io.File;
import java.util.Random;
/**
* Config:
*
* 1. Overall and absolute maximum of temp work directories
* 2. Maximum number of temp work directories pooled overall
* 3. Maximum number of temp work directories pooled for one master repository
*/
public class GitWorkdirPool {
private final Random random = new Random();
private final File poolDirectory;
public GitWorkdirPool() {
this(new File(System.getProperty("java.io.tmpdir")));
}
public GitWorkdirPool(File poolDirectory) {
this.poolDirectory = poolDirectory;
}
public CloseableWrapper<Repository> getWorkingCopy(File bareRepository) {
try {
Git clone = cloneRepository(bareRepository, new File(poolDirectory, Long.toString(random.nextLong())));
return new CloseableWrapper<>(clone.getRepository(), r -> clone.close());
} catch (GitAPIException e) {
throw new InternalRepositoryException("could not clone working copy of repository", e);
}
}
protected Git cloneRepository(File bareRepository, File target) throws GitAPIException {
return Git.cloneRepository()
.setURI(bareRepository.getAbsolutePath())
.setDirectory(target)
.call();
}
}

View File

@@ -0,0 +1,35 @@
package sonia.scm.repository.spi;
import org.eclipse.jgit.merge.MergeStrategy;
import org.eclipse.jgit.merge.ResolveMerger;
import sonia.scm.repository.CloseableWrapper;
import sonia.scm.repository.GitWorkdirPool;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.Repository;
import java.io.IOException;
public class GitMergeCommand extends AbstractGitCommand implements MergeCommand {
private final GitWorkdirPool workdirPool;
GitMergeCommand(GitContext context, Repository repository, GitWorkdirPool workdirPool) {
super(context, repository);
this.workdirPool = workdirPool;
}
@Override
public boolean merge(MergeCommandRequest request) {
try (CloseableWrapper<org.eclipse.jgit.lib.Repository> workingCopy = workdirPool.getWorkingCopy(context.open().getDirectory())) {
org.eclipse.jgit.lib.Repository repository = workingCopy.get();
ResolveMerger merger = (ResolveMerger) MergeStrategy.RECURSIVE.newMerger(repository);
boolean mergeResult = merger.merge(repository.resolve(request.getBranchToMerge()), repository.resolve(request.getTargetBranch()));
if (mergeResult) {
// TODO push and verify push was successful
}
return mergeResult;
} catch (IOException e) {
throw new InternalRepositoryException(e);
}
}
}

View File

@@ -245,6 +245,12 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider
public MergeDryRunCommand getMergeDryRunCommand() {
return new GitMergeDryRunCommand(context, repository);
}
@Override
public MergeCommand getMergeCommand() {
return new GitMergeCommand(context, repository, handler.getWorkdirPool());
}
//~--- fields ---------------------------------------------------------------
/** Field description */

View File

@@ -0,0 +1,29 @@
package sonia.scm.repository;
import org.junit.Test;
import java.util.function.Consumer;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
public class CloseableWrapperTest {
@Test
public void x() {
Consumer<String> wrapped = new Consumer<String>() {
// no this cannot be replaced with a lambda because otherwise we could not use Mockito#spy
@Override
public void accept(String s) {
}
};
Consumer<String> closer = spy(wrapped);
try (CloseableWrapper<String> wrapper = new CloseableWrapper<>("test", closer)) {
// nothing to do here
}
verify(closer).accept("test");
}
}

View File

@@ -0,0 +1,59 @@
package sonia.scm.repository;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import sonia.scm.repository.spi.AbstractGitCommandTestBase;
import java.io.File;
import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
public class GitWorkdirPoolTest extends AbstractGitCommandTestBase {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void emptyPoolShouldCreateNewWorkdir() throws IOException {
GitWorkdirPool pool = new GitWorkdirPool(temporaryFolder.newFolder());
File masterRepo = createRepositoryDirectory();
CloseableWrapper<Repository> workingCopy = pool.getWorkingCopy(masterRepo);
assertThat(workingCopy)
.isNotNull()
.extracting(w -> w.get().getDirectory())
.isNotEqualTo(masterRepo);
}
@Test
public void cloneFromPoolShouldBeClosed() throws IOException {
PoolWithSpy pool = new PoolWithSpy(temporaryFolder.newFolder());
File masterRepo = createRepositoryDirectory();
try (CloseableWrapper<Repository> workingCopy = pool.getWorkingCopy(masterRepo)) {
assertThat(workingCopy).isNotNull();
}
verify(pool.createdClone).close();
}
private static class PoolWithSpy extends GitWorkdirPool {
PoolWithSpy(File poolDirectory) {
super(poolDirectory);
}
Git createdClone;
@Override
protected Git cloneRepository(File bareRepository, File destination) throws GitAPIException {
createdClone = spy(super.cloneRepository(bareRepository, destination));
return createdClone;
}
}
}

View File

@@ -50,8 +50,10 @@ public class AbstractGitCommandTestBase extends ZippedRepositoryTestBase
@After
public void close()
{
if (context != null) {
context.close();
}
}
/**
* Method description