mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-10 15:35:49 +01:00
merged
This commit is contained in:
@@ -19,10 +19,10 @@ public abstract class SimpleWorkdirFactory<R, C> implements WorkdirFactory<R, C>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorkingCopy<R> createWorkingCopy(C context) {
|
public WorkingCopy<R> createWorkingCopy(C context, String initialBranch) {
|
||||||
try {
|
try {
|
||||||
File directory = workdirProvider.createNewWorkdir();
|
File directory = workdirProvider.createNewWorkdir();
|
||||||
ParentAndClone<R> parentAndClone = cloneRepository(context, directory);
|
ParentAndClone<R> parentAndClone = cloneRepository(context, directory, initialBranch);
|
||||||
return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), this::close, directory);
|
return new WorkingCopy<>(parentAndClone.getClone(), parentAndClone.getParent(), this::close, directory);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InternalRepositoryException(getScmRepository(context), "could not clone repository in temporary directory", e);
|
throw new InternalRepositoryException(getScmRepository(context), "could not clone repository in temporary directory", e);
|
||||||
@@ -35,7 +35,7 @@ public abstract class SimpleWorkdirFactory<R, C> implements WorkdirFactory<R, C>
|
|||||||
// We do allow implementations to throw arbitrary exceptions here, so that we can handle them in close
|
// We do allow implementations to throw arbitrary exceptions here, so that we can handle them in close
|
||||||
protected abstract void closeRepository(R repository) throws Exception;
|
protected abstract void closeRepository(R repository) throws Exception;
|
||||||
|
|
||||||
protected abstract ParentAndClone<R> cloneRepository(C context, File target) throws IOException;
|
protected abstract ParentAndClone<R> cloneRepository(C context, File target, String initialBranch) throws IOException;
|
||||||
|
|
||||||
private void close(R repository) {
|
private void close(R repository) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package sonia.scm.repository.util;
|
package sonia.scm.repository.util;
|
||||||
|
|
||||||
public interface WorkdirFactory<R, C> {
|
public interface WorkdirFactory<R, C> {
|
||||||
WorkingCopy<R> createWorkingCopy(C context);
|
WorkingCopy<R> createWorkingCopy(C context, String initialBranch);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ public class SimpleWorkdirFactoryTest {
|
|||||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
private SimpleWorkdirFactory<Closeable, Context> simpleWorkdirFactory;
|
private SimpleWorkdirFactory<Closeable, Context> simpleWorkdirFactory;
|
||||||
|
|
||||||
|
private String initialBranchForLastCloneCall;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void initFactory() throws IOException {
|
public void initFactory() throws IOException {
|
||||||
WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder());
|
WorkdirProvider workdirProvider = new WorkdirProvider(temporaryFolder.newFolder());
|
||||||
@@ -41,7 +43,8 @@ public class SimpleWorkdirFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ParentAndClone<Closeable> cloneRepository(Context context, File target) {
|
protected ParentAndClone<Closeable> cloneRepository(Context context, File target, String initialBranch) {
|
||||||
|
initialBranchForLastCloneCall = initialBranch;
|
||||||
return new ParentAndClone<>(parent, clone);
|
return new ParentAndClone<>(parent, clone);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -50,7 +53,7 @@ public class SimpleWorkdirFactoryTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldCreateParentAndClone() {
|
public void shouldCreateParentAndClone() {
|
||||||
Context context = new Context();
|
Context context = new Context();
|
||||||
try (WorkingCopy<Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context)) {
|
try (WorkingCopy<Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {
|
||||||
assertThat(workingCopy.getCentralRepository()).isSameAs(parent);
|
assertThat(workingCopy.getCentralRepository()).isSameAs(parent);
|
||||||
assertThat(workingCopy.getWorkingRepository()).isSameAs(clone);
|
assertThat(workingCopy.getWorkingRepository()).isSameAs(clone);
|
||||||
}
|
}
|
||||||
@@ -59,7 +62,7 @@ public class SimpleWorkdirFactoryTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldCloseParent() throws IOException {
|
public void shouldCloseParent() throws IOException {
|
||||||
Context context = new Context();
|
Context context = new Context();
|
||||||
try (WorkingCopy<Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context)) {}
|
try (WorkingCopy<Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {}
|
||||||
|
|
||||||
verify(parent).close();
|
verify(parent).close();
|
||||||
}
|
}
|
||||||
@@ -67,10 +70,18 @@ public class SimpleWorkdirFactoryTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldCloseClone() throws IOException {
|
public void shouldCloseClone() throws IOException {
|
||||||
Context context = new Context();
|
Context context = new Context();
|
||||||
try (WorkingCopy<Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context)) {}
|
try (WorkingCopy<Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context, null)) {}
|
||||||
|
|
||||||
verify(clone).close();
|
verify(clone).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPropagateInitialBranch() {
|
||||||
|
Context context = new Context();
|
||||||
|
try (WorkingCopy<Closeable> workingCopy = simpleWorkdirFactory.createWorkingCopy(context, "some")) {
|
||||||
|
assertThat(initialBranchForLastCloneCall).isEqualTo("some");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class Context {}
|
private static class Context {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,8 +140,8 @@ class AbstractGitCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<R, W extends GitCloneWorker<R>> R inClone(Function<Git, W> workerSupplier, GitWorkdirFactory workdirFactory) {
|
<R, W extends GitCloneWorker<R>> R inClone(Function<Git, W> workerSupplier, GitWorkdirFactory workdirFactory, String initialBranch) {
|
||||||
try (WorkingCopy<Repository> workingCopy = workdirFactory.createWorkingCopy(context)) {
|
try (WorkingCopy<Repository> workingCopy = workdirFactory.createWorkingCopy(context, initialBranch)) {
|
||||||
Repository repository = workingCopy.getWorkingRepository();
|
Repository repository = workingCopy.getWorkingRepository();
|
||||||
logger.debug("cloned repository to folder {}", repository.getWorkTree());
|
logger.debug("cloned repository to folder {}", repository.getWorkTree());
|
||||||
return workerSupplier.apply(new Git(repository)).run();
|
return workerSupplier.apply(new Git(repository)).run();
|
||||||
|
|||||||
@@ -58,11 +58,8 @@ public class GitBranchCommand extends AbstractGitCommand implements BranchComman
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Branch branch(BranchRequest request) {
|
public Branch branch(BranchRequest request) {
|
||||||
try (WorkingCopy<org.eclipse.jgit.lib.Repository> workingCopy = workdirFactory.createWorkingCopy(context)) {
|
try (WorkingCopy<org.eclipse.jgit.lib.Repository> workingCopy = workdirFactory.createWorkingCopy(context, request.getParentBranch())) {
|
||||||
Git clone = new Git(workingCopy.getWorkingRepository());
|
Git clone = new Git(workingCopy.getWorkingRepository());
|
||||||
if (request.getParentBranch() != null) {
|
|
||||||
clone.checkout().setName("origin/" + request.getParentBranch()).call();
|
|
||||||
}
|
|
||||||
Ref ref = clone.branchCreate().setName(request.getNewBranch()).call();
|
Ref ref = clone.branchCreate().setName(request.getNewBranch()).call();
|
||||||
Iterable<PushResult> call = clone.push().add(request.getNewBranch()).call();
|
Iterable<PushResult> call = clone.push().add(request.getNewBranch()).call();
|
||||||
StreamSupport.stream(call.spliterator(), false)
|
StreamSupport.stream(call.spliterator(), false)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MergeCommandResult merge(MergeCommandRequest request) {
|
public MergeCommandResult merge(MergeCommandRequest request) {
|
||||||
return inClone(clone -> new MergeWorker(clone, request), workdirFactory);
|
return inClone(clone -> new MergeWorker(clone, request), workdirFactory, request.getTargetBranch());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -72,7 +72,6 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
MergeCommandResult run() throws IOException {
|
MergeCommandResult run() throws IOException {
|
||||||
checkOutTargetBranch();
|
|
||||||
MergeResult result = doMergeInClone();
|
MergeResult result = doMergeInClone();
|
||||||
if (result.getMergeStatus().isSuccessful()) {
|
if (result.getMergeStatus().isSuccessful()) {
|
||||||
doCommit();
|
doCommit();
|
||||||
@@ -83,10 +82,6 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkOutTargetBranch() throws IOException {
|
|
||||||
checkOutBranch(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MergeResult doMergeInClone() throws IOException {
|
private MergeResult doMergeInClone() throws IOException {
|
||||||
MergeResult result;
|
MergeResult result;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package sonia.scm.repository.spi;
|
|||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
|
||||||
import org.eclipse.jgit.lib.Ref;
|
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
import sonia.scm.ConcurrentModificationException;
|
import sonia.scm.ConcurrentModificationException;
|
||||||
import sonia.scm.ContextEntry;
|
import sonia.scm.ContextEntry;
|
||||||
@@ -25,7 +23,6 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
|||||||
import static sonia.scm.AlreadyExistsException.alreadyExists;
|
import static sonia.scm.AlreadyExistsException.alreadyExists;
|
||||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||||
import static sonia.scm.NotFoundException.notFound;
|
import static sonia.scm.NotFoundException.notFound;
|
||||||
import static sonia.scm.ScmConstraintViolationException.Builder.doThrow;
|
|
||||||
|
|
||||||
public class GitModifyCommand extends AbstractGitCommand implements ModifyCommand {
|
public class GitModifyCommand extends AbstractGitCommand implements ModifyCommand {
|
||||||
|
|
||||||
@@ -38,7 +35,7 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String execute(ModifyCommandRequest request) {
|
public String execute(ModifyCommandRequest request) {
|
||||||
return inClone(clone -> new ModifyWorker(clone, request), workdirFactory);
|
return inClone(clone -> new ModifyWorker(clone, request), workdirFactory, request.getBranch());
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ModifyWorker extends GitCloneWorker<String> implements Worker {
|
private class ModifyWorker extends GitCloneWorker<String> implements Worker {
|
||||||
@@ -54,11 +51,6 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
String run() throws IOException {
|
String run() throws IOException {
|
||||||
if (!StringUtils.isEmpty(request.getBranch())) {
|
|
||||||
checkOutBranch(request.getBranch());
|
|
||||||
}
|
|
||||||
Ref head = getClone().getRepository().exactRef(Constants.HEAD);
|
|
||||||
doThrow().violation("branch has to be a valid branch, no revision", "branch", request.getBranch()).when(head == null || !head.isSymbolic());
|
|
||||||
getClone().getRepository().getFullBranch();
|
getClone().getRepository().getFullBranch();
|
||||||
if (!StringUtils.isEmpty(request.getExpectedRevision())) {
|
if (!StringUtils.isEmpty(request.getExpectedRevision())) {
|
||||||
if (!request.getExpectedRevision().equals(getCurrentRevision().getName())) {
|
if (!request.getExpectedRevision().equals(getCurrentRevision().getName())) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package sonia.scm.repository.spi;
|
|||||||
|
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.lib.Constants;
|
||||||
|
import org.eclipse.jgit.lib.Ref;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.transport.ScmTransportProtocol;
|
import org.eclipse.jgit.transport.ScmTransportProtocol;
|
||||||
import sonia.scm.repository.GitWorkdirFactory;
|
import sonia.scm.repository.GitWorkdirFactory;
|
||||||
@@ -11,6 +13,10 @@ import sonia.scm.repository.util.WorkdirProvider;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||||
|
import static sonia.scm.NotFoundException.notFound;
|
||||||
|
|
||||||
public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory<Repository, GitContext> implements GitWorkdirFactory {
|
public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory<Repository, GitContext> implements GitWorkdirFactory {
|
||||||
|
|
||||||
@@ -20,14 +26,23 @@ public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory<Repository, Gi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParentAndClone<Repository> cloneRepository(GitContext context, File target) {
|
public ParentAndClone<Repository> cloneRepository(GitContext context, File target, String initialBranch) {
|
||||||
try {
|
try {
|
||||||
return new ParentAndClone<>(null, Git.cloneRepository()
|
Repository clone = Git.cloneRepository()
|
||||||
.setURI(createScmTransportProtocolUri(context.getDirectory()))
|
.setURI(createScmTransportProtocolUri(context.getDirectory()))
|
||||||
.setDirectory(target)
|
.setDirectory(target)
|
||||||
|
.setBranch(initialBranch)
|
||||||
.call()
|
.call()
|
||||||
.getRepository());
|
.getRepository();
|
||||||
} catch (GitAPIException e) {
|
|
||||||
|
Ref head = clone.exactRef(Constants.HEAD);
|
||||||
|
|
||||||
|
if (head == null || !head.isSymbolic() || (initialBranch != null && !head.getTarget().getName().endsWith(initialBranch))) {
|
||||||
|
throw notFound(entity("Branch", initialBranch).in(context.getRepository()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ParentAndClone<>(null, clone);
|
||||||
|
} catch (GitAPIException | IOException e) {
|
||||||
throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e);
|
throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -263,8 +263,8 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase {
|
|||||||
command.execute(request);
|
command.execute(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ScmConstraintViolationException.class)
|
@Test(expected = NotFoundException.class)
|
||||||
public void shouldFailWithConstraintViolationIfBranchIsNoBranch() throws IOException {
|
public void shouldFailWithNotFoundExceptionIfBranchIsNoBranch() throws IOException {
|
||||||
File newFile = Files.write(temporaryFolder.newFile().toPath(), "irrelevant\n".getBytes()).toFile();
|
File newFile = Files.write(temporaryFolder.newFile().toPath(), "irrelevant\n".getBytes()).toFile();
|
||||||
|
|
||||||
GitModifyCommand command = createCommand();
|
GitModifyCommand command = createCommand();
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import com.github.sdorra.shiro.ShiroRule;
|
||||||
|
import com.github.sdorra.shiro.SubjectAware;
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.errors.CorruptObjectException;
|
||||||
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
|
import org.eclipse.jgit.lib.ObjectReader;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
import sonia.scm.ScmConstraintViolationException;
|
||||||
|
import sonia.scm.repository.Person;
|
||||||
|
import sonia.scm.repository.util.WorkdirProvider;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@SubjectAware(configuration = "classpath:sonia/scm/configuration/shiro.ini", username = "admin", password = "secret")
|
||||||
|
public class GitModifyCommand_withEmptyRepositoryTest extends AbstractGitCommandTestBase {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
@Rule
|
||||||
|
public BindTransportProtocolRule transportProtocolRule = new BindTransportProtocolRule();
|
||||||
|
@Rule
|
||||||
|
public ShiroRule shiro = new ShiroRule();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateNewFileInEmptyRepository() throws IOException, GitAPIException {
|
||||||
|
File newFile = Files.write(temporaryFolder.newFile().toPath(), "new content".getBytes()).toFile();
|
||||||
|
|
||||||
|
GitModifyCommand command = createCommand();
|
||||||
|
|
||||||
|
ModifyCommandRequest request = new ModifyCommandRequest();
|
||||||
|
request.setCommitMessage("test commit");
|
||||||
|
request.addRequest(new ModifyCommandRequest.CreateFileRequest("new_file", newFile, false));
|
||||||
|
request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det"));
|
||||||
|
|
||||||
|
command.execute(request);
|
||||||
|
|
||||||
|
TreeAssertions assertions = canonicalTreeParser -> assertThat(canonicalTreeParser.findFile("new_file")).isTrue();
|
||||||
|
|
||||||
|
assertInTree(assertions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getZippedRepositoryResource() {
|
||||||
|
return "sonia/scm/repository/spi/scm-git-empty-repo.zip";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertInTree(TreeAssertions assertions) throws IOException, GitAPIException {
|
||||||
|
try (Git git = new Git(createContext().open())) {
|
||||||
|
RevCommit lastCommit = getLastCommit(git);
|
||||||
|
try (RevWalk walk = new RevWalk(git.getRepository())) {
|
||||||
|
RevCommit commit = walk.parseCommit(lastCommit);
|
||||||
|
ObjectId treeId = commit.getTree().getId();
|
||||||
|
try (ObjectReader reader = git.getRepository().newObjectReader()) {
|
||||||
|
assertions.checkAssertions(new CanonicalTreeParser(null, reader, treeId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RevCommit getLastCommit(Git git) throws GitAPIException {
|
||||||
|
return git.log().setMaxCount(1).call().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
private GitModifyCommand createCommand() {
|
||||||
|
return new GitModifyCommand(createContext(), repository, new SimpleGitWorkdirFactory(new WorkdirProvider()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface TreeAssertions {
|
||||||
|
void checkAssertions(CanonicalTreeParser treeParser) throws CorruptObjectException;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,8 +20,6 @@ import java.io.IOException;
|
|||||||
import static com.google.inject.util.Providers.of;
|
import static com.google.inject.util.Providers.of;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase {
|
public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase {
|
||||||
|
|
||||||
@@ -43,11 +41,11 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void emptyPoolShouldCreateNewWorkdir() throws IOException {
|
public void emptyPoolShouldCreateNewWorkdir() {
|
||||||
SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider);
|
SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider);
|
||||||
File masterRepo = createRepositoryDirectory();
|
File masterRepo = createRepositoryDirectory();
|
||||||
|
|
||||||
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext())) {
|
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext(), null)) {
|
||||||
|
|
||||||
assertThat(workingCopy.getDirectory())
|
assertThat(workingCopy.getDirectory())
|
||||||
.exists()
|
.exists()
|
||||||
@@ -61,25 +59,37 @@ public class SimpleGitWorkdirFactoryTest extends AbstractGitCommandTestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cloneFromPoolShouldNotBeReused() throws IOException {
|
public void shouldCheckoutInitialBranch() {
|
||||||
|
SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider);
|
||||||
|
|
||||||
|
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext(), "test-branch")) {
|
||||||
|
assertThat(new File(workingCopy.getWorkingRepository().getWorkTree(), "a.txt"))
|
||||||
|
.exists()
|
||||||
|
.isFile()
|
||||||
|
.hasContent("a and b");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cloneFromPoolShouldNotBeReused() {
|
||||||
SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider);
|
SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider);
|
||||||
|
|
||||||
File firstDirectory;
|
File firstDirectory;
|
||||||
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext())) {
|
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext(), null)) {
|
||||||
firstDirectory = workingCopy.getDirectory();
|
firstDirectory = workingCopy.getDirectory();
|
||||||
}
|
}
|
||||||
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext())) {
|
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext(), null)) {
|
||||||
File secondDirectory = workingCopy.getDirectory();
|
File secondDirectory = workingCopy.getDirectory();
|
||||||
assertThat(secondDirectory).isNotEqualTo(firstDirectory);
|
assertThat(secondDirectory).isNotEqualTo(firstDirectory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void cloneFromPoolShouldBeDeletedOnClose() throws IOException {
|
public void cloneFromPoolShouldBeDeletedOnClose() {
|
||||||
SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider);
|
SimpleGitWorkdirFactory factory = new SimpleGitWorkdirFactory(workdirProvider);
|
||||||
|
|
||||||
File directory;
|
File directory;
|
||||||
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext())) {
|
try (WorkingCopy<Repository> workingCopy = factory.createWorkingCopy(createContext(), null)) {
|
||||||
directory = workingCopy.getWorkingRepository().getWorkTree();
|
directory = workingCopy.getWorkingRepository().getWorkTree();
|
||||||
}
|
}
|
||||||
assertThat(directory).doesNotExist();
|
assertThat(directory).doesNotExist();
|
||||||
|
|||||||
Binary file not shown.
@@ -33,19 +33,15 @@ package sonia.scm.repository.spi;
|
|||||||
import com.aragost.javahg.Changeset;
|
import com.aragost.javahg.Changeset;
|
||||||
import com.aragost.javahg.commands.CommitCommand;
|
import com.aragost.javahg.commands.CommitCommand;
|
||||||
import com.aragost.javahg.commands.PullCommand;
|
import com.aragost.javahg.commands.PullCommand;
|
||||||
import com.aragost.javahg.commands.UpdateCommand;
|
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.repository.Branch;
|
import sonia.scm.repository.Branch;
|
||||||
import sonia.scm.repository.InternalRepositoryException;
|
|
||||||
import sonia.scm.repository.Repository;
|
import sonia.scm.repository.Repository;
|
||||||
import sonia.scm.repository.api.BranchRequest;
|
import sonia.scm.repository.api.BranchRequest;
|
||||||
import sonia.scm.repository.util.WorkingCopy;
|
import sonia.scm.repository.util.WorkingCopy;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mercurial implementation of the {@link BranchCommand}.
|
* Mercurial implementation of the {@link BranchCommand}.
|
||||||
* Note that this creates an empty commit to "persist" the new branch.
|
* Note that this creates an empty commit to "persist" the new branch.
|
||||||
@@ -63,11 +59,9 @@ public class HgBranchCommand extends AbstractCommand implements BranchCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Branch branch(BranchRequest request) {
|
public Branch branch(BranchRequest request) {
|
||||||
try (WorkingCopy<com.aragost.javahg.Repository> workingCopy = workdirFactory.createWorkingCopy(getContext())) {
|
try (WorkingCopy<com.aragost.javahg.Repository> workingCopy = workdirFactory.createWorkingCopy(getContext(), request.getParentBranch())) {
|
||||||
com.aragost.javahg.Repository repository = workingCopy.getWorkingRepository();
|
com.aragost.javahg.Repository repository = workingCopy.getWorkingRepository();
|
||||||
|
|
||||||
checkoutParentBranchIfSpecified(request, repository);
|
|
||||||
|
|
||||||
Changeset emptyChangeset = createNewBranchWithEmptyCommit(request, repository);
|
Changeset emptyChangeset = createNewBranchWithEmptyCommit(request, repository);
|
||||||
|
|
||||||
LOG.debug("Created new branch '{}' in repository {} with changeset {}",
|
LOG.debug("Created new branch '{}' in repository {} with changeset {}",
|
||||||
@@ -79,16 +73,6 @@ public class HgBranchCommand extends AbstractCommand implements BranchCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkoutParentBranchIfSpecified(BranchRequest request, com.aragost.javahg.Repository repository) {
|
|
||||||
if (request.getParentBranch() != null) {
|
|
||||||
try {
|
|
||||||
UpdateCommand.on(repository).rev(request.getParentBranch()).execute();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new InternalRepositoryException(getRepository(), "Could not check out parent branch " + request.getParentBranch(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Changeset createNewBranchWithEmptyCommit(BranchRequest request, com.aragost.javahg.Repository repository) {
|
private Changeset createNewBranchWithEmptyCommit(BranchRequest request, com.aragost.javahg.Repository repository) {
|
||||||
com.aragost.javahg.commands.BranchCommand.on(repository).set(request.getNewBranch());
|
com.aragost.javahg.commands.BranchCommand.on(repository).set(request.getNewBranch());
|
||||||
User currentUser = SecurityUtils.getSubject().getPrincipals().oneByType(User.class);
|
User currentUser = SecurityUtils.getSubject().getPrincipals().oneByType(User.class);
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package sonia.scm.repository.spi;
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
|
import com.aragost.javahg.BaseRepository;
|
||||||
import com.aragost.javahg.Repository;
|
import com.aragost.javahg.Repository;
|
||||||
import com.aragost.javahg.commands.CloneCommand;
|
import com.aragost.javahg.commands.CloneCommand;
|
||||||
import com.aragost.javahg.commands.PullCommand;
|
import com.aragost.javahg.commands.PullCommand;
|
||||||
|
import com.aragost.javahg.commands.flags.CloneCommandFlags;
|
||||||
import sonia.scm.repository.util.SimpleWorkdirFactory;
|
import sonia.scm.repository.util.SimpleWorkdirFactory;
|
||||||
import sonia.scm.repository.util.WorkdirProvider;
|
import sonia.scm.repository.util.WorkdirProvider;
|
||||||
import sonia.scm.web.HgRepositoryEnvironmentBuilder;
|
import sonia.scm.web.HgRepositoryEnvironmentBuilder;
|
||||||
@@ -24,12 +26,19 @@ public class SimpleHgWorkdirFactory extends SimpleWorkdirFactory<Repository, HgC
|
|||||||
this.hgRepositoryEnvironmentBuilder = hgRepositoryEnvironmentBuilder;
|
this.hgRepositoryEnvironmentBuilder = hgRepositoryEnvironmentBuilder;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public ParentAndClone<Repository> cloneRepository(HgCommandContext context, File target) throws IOException {
|
public ParentAndClone<Repository> cloneRepository(HgCommandContext context, File target, String initialBranch) throws IOException {
|
||||||
BiConsumer<sonia.scm.repository.Repository, Map<String, String>> repositoryMapBiConsumer =
|
BiConsumer<sonia.scm.repository.Repository, Map<String, String>> repositoryMapBiConsumer =
|
||||||
(repository, environment) -> hgRepositoryEnvironmentBuilder.get().buildFor(repository, null, environment);
|
(repository, environment) -> hgRepositoryEnvironmentBuilder.get().buildFor(repository, null, environment);
|
||||||
Repository centralRepository = context.openWithSpecialEnvironment(repositoryMapBiConsumer);
|
Repository centralRepository = context.openWithSpecialEnvironment(repositoryMapBiConsumer);
|
||||||
CloneCommand.on(centralRepository).execute(target.getAbsolutePath());
|
CloneCommand cloneCommand = CloneCommandFlags.on(centralRepository);
|
||||||
return new ParentAndClone<>(centralRepository, Repository.open(target));
|
if (initialBranch != null) {
|
||||||
|
cloneCommand.updaterev(initialBranch);
|
||||||
|
}
|
||||||
|
cloneCommand.execute(target.getAbsolutePath());
|
||||||
|
|
||||||
|
BaseRepository clone = Repository.open(target);
|
||||||
|
|
||||||
|
return new ParentAndClone<>(centralRepository, clone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package sonia.scm.repository.spi;
|
|||||||
|
|
||||||
import com.aragost.javahg.commands.PullCommand;
|
import com.aragost.javahg.commands.PullCommand;
|
||||||
import com.google.inject.util.Providers;
|
import com.google.inject.util.Providers;
|
||||||
import org.assertj.core.api.Assertions;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import sonia.scm.repository.Branch;
|
import sonia.scm.repository.Branch;
|
||||||
import sonia.scm.repository.HgTestUtil;
|
import sonia.scm.repository.HgTestUtil;
|
||||||
@@ -10,30 +10,48 @@ import sonia.scm.repository.api.BranchRequest;
|
|||||||
import sonia.scm.repository.util.WorkdirProvider;
|
import sonia.scm.repository.util.WorkdirProvider;
|
||||||
import sonia.scm.web.HgRepositoryEnvironmentBuilder;
|
import sonia.scm.web.HgRepositoryEnvironmentBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class HgBranchCommandTest extends AbstractHgCommandTestBase {
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@Test
|
|
||||||
public void shouldCreateBranch() throws IOException {
|
|
||||||
Assertions.assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isEmpty();
|
|
||||||
|
|
||||||
|
public class HgBranchCommandTest extends AbstractHgCommandTestBase {
|
||||||
|
|
||||||
|
private SimpleHgWorkdirFactory workdirFactory;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void initWorkdirFactory() {
|
||||||
HgRepositoryEnvironmentBuilder hgRepositoryEnvironmentBuilder =
|
HgRepositoryEnvironmentBuilder hgRepositoryEnvironmentBuilder =
|
||||||
new HgRepositoryEnvironmentBuilder(handler, HgTestUtil.createHookManager());
|
new HgRepositoryEnvironmentBuilder(handler, HgTestUtil.createHookManager());
|
||||||
|
|
||||||
SimpleHgWorkdirFactory workdirFactory = new SimpleHgWorkdirFactory(Providers.of(hgRepositoryEnvironmentBuilder), new WorkdirProvider()) {
|
workdirFactory = new SimpleHgWorkdirFactory(Providers.of(hgRepositoryEnvironmentBuilder), new WorkdirProvider()) {
|
||||||
@Override
|
@Override
|
||||||
public void configure(PullCommand pullCommand) {
|
public void configure(PullCommand pullCommand) {
|
||||||
// we do not want to configure http hooks in this unit test
|
// we do not want to configure http hooks in this unit test
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateBranch() {
|
||||||
BranchRequest branchRequest = new BranchRequest();
|
BranchRequest branchRequest = new BranchRequest();
|
||||||
branchRequest.setNewBranch("new_branch");
|
branchRequest.setNewBranch("new_branch");
|
||||||
|
|
||||||
new HgBranchCommand(cmdContext, repository, workdirFactory).branch(branchRequest);
|
Branch newBranch = new HgBranchCommand(cmdContext, repository, workdirFactory).branch(branchRequest);
|
||||||
|
|
||||||
Assertions.assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty();
|
assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty();
|
||||||
|
assertThat(cmdContext.open().changeset(newBranch.getRevision()).getParent1().getBranch()).isEqualTo("default");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateBranchOnSpecificParent() {
|
||||||
|
BranchRequest branchRequest = new BranchRequest();
|
||||||
|
branchRequest.setParentBranch("test-branch");
|
||||||
|
branchRequest.setNewBranch("new_branch");
|
||||||
|
|
||||||
|
Branch newBranch = new HgBranchCommand(cmdContext, repository, workdirFactory).branch(branchRequest);
|
||||||
|
|
||||||
|
assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty();
|
||||||
|
assertThat(cmdContext.open().changeset(newBranch.getRevision()).getParent1().getBranch()).isEqualTo("test-branch");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Branch> readBranches() {
|
private List<Branch> readBranches() {
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ const styles = {
|
|||||||
panel: {
|
panel: {
|
||||||
fontSize: "1rem"
|
fontSize: "1rem"
|
||||||
},
|
},
|
||||||
|
/* remove bottom border for collapsed panels */
|
||||||
|
panelCollapsed: {
|
||||||
|
"& .panel-heading": {
|
||||||
|
borderBottom: "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
/* breaks into a second row
|
/* breaks into a second row
|
||||||
when buttons and title become too long */
|
when buttons and title become too long */
|
||||||
level: {
|
level: {
|
||||||
@@ -107,7 +113,7 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
|
|
||||||
toggleCollapse = () => {
|
toggleCollapse = () => {
|
||||||
const { file } = this.props;
|
const { file } = this.props;
|
||||||
if (file && !file.isBinaray) {
|
if (file && !file.isBinary) {
|
||||||
this.setState(state => ({
|
this.setState(state => ({
|
||||||
collapsed: !state.collapsed
|
collapsed: !state.collapsed
|
||||||
}));
|
}));
|
||||||
@@ -275,15 +281,20 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const collapseIcon = !file.isBinary ? (
|
const collapseIcon =
|
||||||
<Icon name={icon} color="inherit" />
|
file && !file.isBinary ? <Icon name={icon} color="inherit" /> : null;
|
||||||
) : null;
|
|
||||||
|
|
||||||
const fileControls = fileControlFactory
|
const fileControls = fileControlFactory
|
||||||
? fileControlFactory(file, this.setCollapse)
|
? fileControlFactory(file, this.setCollapse)
|
||||||
: null;
|
: null;
|
||||||
return (
|
return (
|
||||||
<div className={classNames("panel", classes.panel)}>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"panel",
|
||||||
|
classes.panel,
|
||||||
|
(file && file.isBinary) || collapsed ? classes.panelCollapsed : ""
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
<div className={classNames("level", classes.level)}>
|
<div className={classNames("level", classes.level)}>
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user