mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-01-01 13:19:53 +01:00
Use clone and push to create branches
Generalize workdir creation for git and hg and create branches in clones instead of the scm repository, so that hooks will be fired correctly once the changes are pushed back. Missing: - Evaluation of the git response from the push command - configuration of the hg environment and the authentication, so that the scmhooks.py script can be triggeret correctly and can callback the scm manager
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package sonia.scm.repository;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import sonia.scm.repository.spi.GitContext;
|
||||
import sonia.scm.repository.spi.WorkingCopy;
|
||||
import sonia.scm.repository.util.WorkdirFactory;
|
||||
|
||||
public interface GitWorkdirFactory {
|
||||
WorkingCopy createWorkingCopy(GitContext gitContext);
|
||||
public interface GitWorkdirFactory extends WorkdirFactory<Repository, GitContext> {
|
||||
}
|
||||
|
||||
@@ -35,26 +35,44 @@ package sonia.scm.repository.spi;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.transport.PushResult;
|
||||
import org.eclipse.jgit.transport.RemoteRefUpdate;
|
||||
import sonia.scm.repository.Branch;
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.repository.GitWorkdirFactory;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.util.WorkingCopy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class GitBranchCommand extends AbstractGitCommand implements BranchCommand {
|
||||
|
||||
GitBranchCommand(GitContext context, Repository repository) {
|
||||
private final GitWorkdirFactory workdirFactory;
|
||||
|
||||
GitBranchCommand(GitContext context, Repository repository, GitWorkdirFactory workdirFactory) {
|
||||
super(context, repository);
|
||||
this.workdirFactory = workdirFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Branch branch(String name) throws IOException {
|
||||
try (Git git = new Git(open())) {
|
||||
Ref ref = git.branchCreate().setName(name).call();
|
||||
public Branch branch(String name) {
|
||||
try (WorkingCopy<org.eclipse.jgit.lib.Repository> workingCopy = workdirFactory.createWorkingCopy(context)) {
|
||||
Git clone = new Git(workingCopy.get());
|
||||
Ref ref = clone.branchCreate().setName(name).call();
|
||||
Iterable<PushResult> call = clone.push().add(name).call();
|
||||
StreamSupport.stream(call.spliterator(), false)
|
||||
.flatMap(pushResult -> pushResult.getRemoteUpdates().stream())
|
||||
.filter(remoteRefUpdate -> remoteRefUpdate.getStatus() != RemoteRefUpdate.Status.OK)
|
||||
.findFirst()
|
||||
.ifPresent(this::handlePushError);
|
||||
return Branch.normalBranch(name, GitUtil.getId(ref.getObjectId()));
|
||||
} catch (GitAPIException ex) {
|
||||
throw new InternalRepositoryException(repository, "could not create branch " + name, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePushError(RemoteRefUpdate remoteRefUpdate) {
|
||||
// TODO handle failed remote update
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import sonia.scm.repository.Person;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.repository.api.MergeCommandResult;
|
||||
import sonia.scm.repository.api.MergeDryRunCommandResult;
|
||||
import sonia.scm.repository.util.WorkingCopy;
|
||||
import sonia.scm.user.User;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -48,7 +49,7 @@ public class GitMergeCommand extends AbstractGitCommand implements MergeCommand
|
||||
public MergeCommandResult merge(MergeCommandRequest request) {
|
||||
RepositoryPermissions.push(context.getRepository().getId()).check();
|
||||
|
||||
try (WorkingCopy workingCopy = workdirFactory.createWorkingCopy(context)) {
|
||||
try (WorkingCopy<Repository> workingCopy = workdirFactory.createWorkingCopy(context)) {
|
||||
Repository repository = workingCopy.get();
|
||||
logger.debug("cloned repository to folder {}", repository.getWorkTree());
|
||||
return new MergeWorker(repository, request).merge();
|
||||
|
||||
@@ -129,7 +129,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider
|
||||
@Override
|
||||
public BranchCommand getBranchCommand()
|
||||
{
|
||||
return new GitBranchCommand(context, repository);
|
||||
return new GitBranchCommand(context, repository, handler.getWorkdirFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,59 +9,40 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.repository.GitWorkdirFactory;
|
||||
import sonia.scm.repository.InternalRepositoryException;
|
||||
import sonia.scm.repository.util.SimpleWorkdirFactory;
|
||||
import sonia.scm.repository.util.WorkingCopy;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class SimpleGitWorkdirFactory implements GitWorkdirFactory {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SimpleGitWorkdirFactory.class);
|
||||
|
||||
private final File poolDirectory;
|
||||
public class SimpleGitWorkdirFactory extends SimpleWorkdirFactory<Repository, GitContext> implements GitWorkdirFactory {
|
||||
|
||||
public SimpleGitWorkdirFactory() {
|
||||
this(new File(System.getProperty("java.io.tmpdir"), "scmm-git-pool"));
|
||||
super(null, new GitCloneProvider());
|
||||
}
|
||||
|
||||
public SimpleGitWorkdirFactory(File poolDirectory) {
|
||||
this.poolDirectory = poolDirectory;
|
||||
poolDirectory.mkdirs();
|
||||
super(poolDirectory, null, new GitCloneProvider());
|
||||
}
|
||||
|
||||
public WorkingCopy createWorkingCopy(GitContext gitContext) {
|
||||
try {
|
||||
Repository clone = cloneRepository(gitContext.getDirectory(), createNewWorkdir());
|
||||
return new WorkingCopy(clone, this::close);
|
||||
} catch (GitAPIException e) {
|
||||
throw new InternalRepositoryException(gitContext.getRepository(), "could not clone working copy of repository", e);
|
||||
} catch (IOException e) {
|
||||
throw new InternalRepositoryException(gitContext.getRepository(), "could not create temporary directory for clone of repository", e);
|
||||
private static class GitCloneProvider implements CloneProvider<Repository, GitContext> {
|
||||
|
||||
@Override
|
||||
public Repository cloneRepository(GitContext context, File target) {
|
||||
try {
|
||||
return Git.cloneRepository()
|
||||
.setURI(createScmTransportProtocolUri(context.getDirectory()))
|
||||
.setDirectory(target)
|
||||
.call()
|
||||
.getRepository();
|
||||
} catch (GitAPIException e) {
|
||||
throw new InternalRepositoryException(context.getRepository(), "could not clone working copy of repository", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File createNewWorkdir() throws IOException {
|
||||
return Files.createTempDirectory(poolDirectory.toPath(),"workdir").toFile();
|
||||
}
|
||||
|
||||
protected Repository cloneRepository(File bareRepository, File target) throws GitAPIException {
|
||||
return Git.cloneRepository()
|
||||
.setURI(createScmTransportProtocolUri(bareRepository))
|
||||
.setDirectory(target)
|
||||
.call()
|
||||
.getRepository();
|
||||
}
|
||||
|
||||
private String createScmTransportProtocolUri(File bareRepository) {
|
||||
return ScmTransportProtocol.NAME + "://" + bareRepository.getAbsolutePath();
|
||||
}
|
||||
|
||||
private void close(Repository repository) {
|
||||
repository.close();
|
||||
try {
|
||||
FileUtils.delete(repository.getWorkTree(), FileUtils.RECURSIVE);
|
||||
} catch (IOException e) {
|
||||
logger.warn("could not delete temporary git workdir '{}'", repository.getWorkTree(), e);
|
||||
private String createScmTransportProtocolUri(File bareRepository) {
|
||||
return ScmTransportProtocol.NAME + "://" + bareRepository.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package sonia.scm.repository.spi;
|
||||
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import sonia.scm.repository.CloseableWrapper;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class WorkingCopy extends CloseableWrapper<Repository> {
|
||||
WorkingCopy(Repository wrapped, Consumer<Repository> cleanup) {
|
||||
super(wrapped, cleanup);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user