diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java index 6e69a2c5ba..a4b416420d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitMergeCommand.java @@ -1,8 +1,11 @@ package sonia.scm.repository.spi; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.merge.ResolveMerger; import org.eclipse.jgit.lib.Repository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.repository.GitWorkdirFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.api.MergeCommandResult; @@ -12,23 +15,20 @@ import java.io.IOException; public class GitMergeCommand extends AbstractGitCommand implements MergeCommand { - private final GitWorkdirFactory workdirPool; + private static final Logger logger = LoggerFactory.getLogger(GitMergeCommand.class); - GitMergeCommand(GitContext context, sonia.scm.repository.Repository repository, GitWorkdirFactory workdirPool) { + private final GitWorkdirFactory workdirFactory; + + GitMergeCommand(GitContext context, sonia.scm.repository.Repository repository, GitWorkdirFactory workdirFactory) { super(context, repository); - this.workdirPool = workdirPool; + this.workdirFactory = workdirFactory; } @Override public MergeCommandResult merge(MergeCommandRequest request) { - try (WorkingCopy workingCopy = workdirPool.createWorkingCopy(context)) { + try (WorkingCopy workingCopy = workdirFactory.createWorkingCopy(context)) { 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 new MergeCommandResult(mergeResult); + return new MergeWorker(repository).merge(request); } catch (IOException e) { throw new InternalRepositoryException(e); } @@ -44,4 +44,34 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand throw new InternalRepositoryException(e); } } + + private static class MergeWorker { + + private final Repository clone; + private MergeWorker(Repository clone) { + this.clone = clone; + } + + private MergeCommandResult merge(MergeCommandRequest request) throws IOException { + ResolveMerger merger = (ResolveMerger) MergeStrategy.RECURSIVE.newMerger(clone); + boolean mergeResult = merger.merge( + resolveRevision(clone, request.getTargetBranch()), + resolveRevision(clone, request.getBranchToMerge()) + ); + if (mergeResult) { + logger.info("Merged branch {} into {}", request.getBranchToMerge(), request.getTargetBranch()); + // TODO commit, push and verify push was successful + } + return new MergeCommandResult(mergeResult); + } + + private ObjectId resolveRevision(Repository repository, String branchToMerge) throws IOException { + ObjectId resolved = repository.resolve(branchToMerge); + if (resolved == null) { + return repository.resolve("origin/" + branchToMerge); + } else { + return resolved; + } + } + } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java index 3c58916807..bd140c68cb 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitMergeCommandTest.java @@ -3,7 +3,22 @@ package sonia.scm.repository.spi; import org.junit.Assert; import org.junit.Test; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + public class GitMergeCommandTest extends AbstractGitCommandTestBase { + + @Test + public void shouldDetectMergeableBranches() { + GitMergeCommand command = createCommand(); + MergeCommandRequest request = new MergeCommandRequest(); + request.setBranchToMerge("mergeable"); + request.setTargetBranch("master"); + + boolean mergeable = command.dryRun(request).isMergeable(); + + assertThat(mergeable).isTrue(); + } + @Test public void shouldDetectNotMergeableBranches() { GitMergeCommand command = createCommand(); @@ -13,10 +28,34 @@ public class GitMergeCommandTest extends AbstractGitCommandTestBase { boolean mergeable = command.dryRun(request).isMergeable(); - Assert.assertFalse(mergeable); + assertThat(mergeable).isFalse(); + } + + @Test + public void shouldMergeMergeableBranches() { + GitMergeCommand command = createCommand(); + MergeCommandRequest request = new MergeCommandRequest(); + request.setTargetBranch("master"); + request.setBranchToMerge("mergeable"); + + boolean mergeable = command.merge(request).isSuccess(); + + assertThat(mergeable).isTrue(); + } + + @Test + public void shouldNotMergeConflictingBranches() { + GitMergeCommand command = createCommand(); + MergeCommandRequest request = new MergeCommandRequest(); + request.setBranchToMerge("test-branch"); + request.setTargetBranch("master"); + + boolean mergeable = command.merge(request).isSuccess(); + + assertThat(mergeable).isFalse(); } private GitMergeCommand createCommand() { - return new GitMergeCommand(createContext(), repository, null); + return new GitMergeCommand(createContext(), repository, new SimpleGitWorkdirFactory()); } } diff --git a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-test.zip b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-test.zip index 3fbab0be38..8f689e9664 100644 Binary files a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-test.zip and b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-test.zip differ