diff --git a/scm-core/src/main/java/sonia/scm/repository/api/BranchCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/BranchCommandBuilder.java new file mode 100644 index 0000000000..b0c6b824ee --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/api/BranchCommandBuilder.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + +package sonia.scm.repository.api; + +//~--- non-JDK imports -------------------------------------------------------- + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import sonia.scm.repository.spi.BranchCommand; + +//~--- JDK imports ------------------------------------------------------------ + +import java.io.IOException; + +/** + * + * @author Sebastian Sdorra + * @since 1.18 + */ +public final class BranchCommandBuilder +{ + + /** + * the logger for BranchCommandBuilder + */ + private static final Logger logger = + LoggerFactory.getLogger(BranchCommandBuilder.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs ... + * + * + * @param command + */ + public BranchCommandBuilder(BranchCommand command) + { + this.command = command; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Method description + * + * + * @param name + * + * @return + * + * @throws IOException + */ + public BranchCommandBuilder branch(String name) throws IOException + { + if (logger.isDebugEnabled()) + { + logger.debug("branch {}", name); + } + + command.branch(name); + + return this; + } + + //~--- fields --------------------------------------------------------------- + + /** Field description */ + private BranchCommand command; +} diff --git a/scm-core/src/main/java/sonia/scm/repository/api/Command.java b/scm-core/src/main/java/sonia/scm/repository/api/Command.java index fa09cea2cb..e380727769 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/Command.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/Command.java @@ -53,6 +53,11 @@ public enum Command */ BRANCHES, + /** + * @since 2.0 + */ + BRANCH, + /** * @since 1.31 */ diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java index ad53c3a8f7..d59362a7f3 100644 --- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java +++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java @@ -165,6 +165,20 @@ public final class RepositoryService implements Closeable { provider.getBranchesCommand(), repository); } + /** + * The branch command creates new branches. + * + * @return instance of {@link BranchCommandBuilder} + * @throws CommandNotSupportedException if the command is not supported + * by the implementation of the repository service provider. + */ + public BranchCommandBuilder getBranchCommand() { + logger.debug("create branch command for repository {}", + repository.getNamespaceAndName()); + + return new BranchCommandBuilder(provider.getBranchCommand()); + } + /** * The browse command allows browsing of a repository. * diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/BranchCommand.java b/scm-core/src/main/java/sonia/scm/repository/spi/BranchCommand.java new file mode 100644 index 0000000000..cbce371f4a --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/repository/spi/BranchCommand.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + +package sonia.scm.repository.spi; + + +import sonia.scm.repository.Branch; + +import java.io.IOException; + +/** + * @since 2.0 + */ +public interface BranchCommand { + Branch branch(String name) throws IOException; +} diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java index 77201d1a72..a82eb7c30a 100644 --- a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java +++ b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java @@ -101,6 +101,17 @@ public abstract class RepositoryServiceProvider implements Closeable throw new CommandNotSupportedException(Command.BRANCHES); } + /** + * Method description + * + * + * @return + */ + public BranchCommand getBranchCommand() + { + throw new CommandNotSupportedException(Command.BRANCH); + } + /** * Method description * diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchCommand.java new file mode 100644 index 0000000000..23be8883fa --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBranchCommand.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + +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 sonia.scm.repository.Branch; +import sonia.scm.repository.GitUtil; +import sonia.scm.repository.InternalRepositoryException; +import sonia.scm.repository.Repository; + +import java.io.IOException; + +public class GitBranchCommand extends AbstractGitCommand implements BranchCommand { + + GitBranchCommand(GitContext context, Repository repository) { + super(context, repository); + } + + @Override + public Branch branch(String name) throws IOException { + try (Git git = new Git(open())) { + Ref ref = git.branchCreate().setName(name).call(); + return Branch.normalBranch(name, GitUtil.getId(ref.getObjectId())); + } catch (GitAPIException ex) { + throw new InternalRepositoryException(repository, "could not create branch " + name, ex); + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index ef3d96d5cb..898c5875d3 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -120,6 +120,18 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider return new GitBranchesCommand(context, repository); } + /** + * Method description + * + * + * @return + */ + @Override + public BranchCommand getBranchCommand() + { + return new GitBranchCommand(context, repository); + } + /** * Method description * diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchCommandTest.java new file mode 100644 index 0000000000..d5dfc17698 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitBranchCommandTest.java @@ -0,0 +1,27 @@ +package sonia.scm.repository.spi; + +import org.assertj.core.api.Assertions; +import org.junit.Test; +import sonia.scm.repository.Branch; + +import java.io.IOException; +import java.util.List; + + +public class GitBranchCommandTest extends AbstractGitCommandTestBase { + + @Test + public void shouldCreateBranch() throws IOException { + GitContext context = createContext(); + + Assertions.assertThat(readBranches(context)).filteredOn(b -> b.getName().equals("new_branch")).isEmpty(); + + new GitBranchCommand(context, repository).branch("new_branch"); + + Assertions.assertThat(readBranches(context)).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty(); + } + + private List readBranches(GitContext context) throws IOException { + return new GitBranchesCommand(context, repository).getBranches(); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java new file mode 100644 index 0000000000..01c5c5fc98 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgBranchCommand.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2014, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ +package sonia.scm.repository.spi; + +import com.aragost.javahg.Changeset; +import com.aragost.javahg.commands.CommitCommand; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.repository.Branch; +import sonia.scm.repository.Repository; + +/** + * Mercurial implementation of the {@link BranchCommand}. + * Note that this creates an empty commit to "persist" the new branch. + */ +public class HgBranchCommand extends AbstractCommand implements BranchCommand { + + private static final Logger LOG = LoggerFactory.getLogger(HgBranchCommand.class); + + HgBranchCommand(HgCommandContext context, Repository repository) { + super(context, repository); + } + + @Override + public Branch branch(String name) { + com.aragost.javahg.Repository repository = open(); + com.aragost.javahg.commands.BranchCommand.on(repository).set(name); + + Changeset emptyChangeset = CommitCommand + .on(repository) + .user("SCM-Manager") + .message("Create new branch " + name) + .execute(); + + LOG.debug("Created new branch '{}' in repository {} with changeset {}", + name, getRepository().getNamespaceAndName(), emptyChangeset.getNode()); + + return Branch.normalBranch(name, emptyChangeset.getNode()); + } +} diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java index 2c18aea2c3..0b88c07cb1 100644 --- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java +++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java @@ -126,6 +126,11 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider return new HgBranchesCommand(context, repository); } + @Override + public BranchCommand getBranchCommand() { + return new HgBranchCommand(context, repository); + } + /** * Method description * @@ -192,6 +197,7 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider * @return the corresponding {@link ModificationsCommand} implemented from the Plugins * @throws CommandNotSupportedException if there is no Implementation */ + @Override public ModificationsCommand getModificationsCommand() { return new HgModificationsCommand(context,repository); } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java new file mode 100644 index 0000000000..8c0b1862d1 --- /dev/null +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgBranchCommandTest.java @@ -0,0 +1,22 @@ +package sonia.scm.repository.spi; + +import org.assertj.core.api.Assertions; +import org.junit.Test; +import sonia.scm.repository.Branch; + +import java.util.List; + +public class HgBranchCommandTest extends AbstractHgCommandTestBase { + @Test + public void x() { + Assertions.assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isEmpty(); + + new HgBranchCommand(cmdContext, repository).branch("new_branch"); + + Assertions.assertThat(readBranches()).filteredOn(b -> b.getName().equals("new_branch")).isNotEmpty(); + } + + private List readBranches() { + return new HgBranchesCommand(cmdContext, repository).getBranches(); + } +}