Add ssh command create-branch for creating branches
This command will allow users to create branches via ssh.
Feature: Issue 1156
Change-Id: I270df6bc3ed95581aa2fc6845c654f2d9a5c72b1
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index b6f7d7c..facc8f2 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -542,13 +542,12 @@
configuration. Users who are members of an owner group can:
* Change the project description
-* Create/delete a branch through the web UI (not SSH)
+* Create a branch through SSH
+* Create/delete a branch through the web UI
* Grant/revoke any access rights, including `Owner`
-Note that project owners implicitly have branch creation or deletion
-through the web UI, but not through SSH. To get SSH branch access
-project owners must grant an access right to a group they are a
-member of, just like for any other user.
+To get SSH branch access project owners must grant an access right to a group
+they are a member of, just like for any other user.
Ownership over a particular branch subspace may be delegated by
entering a branch pattern. To delegate control over all branches
diff --git a/Documentation/cmd-create-branch.txt b/Documentation/cmd-create-branch.txt
new file mode 100644
index 0000000..6e6d561
--- /dev/null
+++ b/Documentation/cmd-create-branch.txt
@@ -0,0 +1,58 @@
+gerrit create-branch
+====================
+
+NAME
+----
+gerrit create-branch - Create a new branch
+
+SYNOPSIS
+--------
+--
+'ssh' -p <port> <host> 'gerrit create-branch'
+ <PROJECT>
+ <NAME>
+ <REVISION>
+--
+
+DESCRIPTION
+-----------
+Creates a new branch for a project.
+
+ACCESS
+------
+Caller should have link:access-control.html#category_create[Create Reference]
+permission on the project.
+
+Administrators do not automatically have permission to create branches. It must
+be granted via the Create Reference permission.
+
+SCRIPTING
+---------
+This command is intended to be used in scripts.
+
+OPTIONS
+-------
+<PROJECT>::
+ Required; name of the project.
+
+<NAME>::
+ Required; name of the branch to be created.
+
+<REVISION>::
+ Required; base revision of the new branch.
+
+EXAMPLES
+--------
+Create a new branch called 'newbranch' from the 'master' branch of
+the project 'myproject'.
+
+====
+ $ ssh -p 29418 review.example.com gerrit create-branch myproject newbranch master
+====
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index 4e62451..6ddfa36 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -96,6 +96,9 @@
Also implements the magic associated with uploading commits for
review. See link:user-upload.html#push_create[Creating Changes].
+link:cmd-create-branch.html[gerrit create-branch]::
+ Create a new project branch.
+
[[admin_commands]]Administrator Commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateBranchCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateBranchCommand.java
new file mode 100644
index 0000000..16ffe28
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/CreateBranchCommand.java
@@ -0,0 +1,59 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.sshd.commands;
+
+import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.projects.BranchApi;
+import com.google.gerrit.extensions.api.projects.BranchInput;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.project.CreateBranch;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.sshd.CommandMetaData;
+import com.google.gerrit.sshd.SshCommand;
+import com.google.inject.Inject;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+import java.io.IOException;
+
+/** Create a new branch. **/
+@CommandMetaData(name = "create-branch", description = "Create a new branch")
+final public class CreateBranchCommand extends SshCommand {
+
+ @Argument(index = 0, required = true, metaVar = "PROJECT", usage = "name of the project")
+ private ProjectControl project;
+
+ @Argument(index = 1, required = true, metaVar = "NAME", usage = "name of branch to be created")
+ private String name;
+
+ @Argument(index = 2, required = true, metaVar = "REVISION", usage = "base revision of the new branch")
+ private String revision;
+
+ @Inject
+ GerritApi gApi;
+
+ @Override
+ protected void run() throws UnloggedFailure {
+ try {
+ BranchInput in = new BranchInput();
+ in.revision = revision;
+ gApi.projects().name(project.getProject().getNameKey().get())
+ .branch(name).create(in);
+ } catch (RestApiException e) {
+ throw new UnloggedFailure(1, "fatal: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/MasterCommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/MasterCommandModule.java
index a8d5c4d..a79e862 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/MasterCommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/MasterCommandModule.java
@@ -31,6 +31,7 @@
command(gerrit, CreateGroupCommand.class);
command(gerrit, RenameGroupCommand.class);
command(gerrit, CreateProjectCommand.class);
+ command(gerrit, CreateBranchCommand.class);
command(gerrit, AdminQueryShell.class);
command(gerrit, SetReviewersCommand.class);
command(gerrit, Receive.class);