Add set-head SSH command

Adds SSH command to change project HEAD reference.

Change-Id: I1a4cb0673eb819fae85e9babdb569ab9785662c8
Signed-off-by: Dariusz Luksza <dariusz@luksza.org>
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index 7c664ac..f3bff7d 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -75,6 +75,9 @@
 link:cmd-review.html[gerrit review]::
 	Verify, approve and/or submit a patch set from the command line.
 
+link:cmd-set-head.html[gerrit set-head]::
+	Change the HEAD reference of a project.
+
 link:cmd-set-reviewers.html[gerrit set-reviewers]::
 	Add or remove reviewers on a change.
 
diff --git a/Documentation/cmd-set-head.txt b/Documentation/cmd-set-head.txt
new file mode 100644
index 0000000..164035e
--- /dev/null
+++ b/Documentation/cmd-set-head.txt
@@ -0,0 +1,46 @@
+= gerrit set-head
+
+== NAME
+gerrit set-head - Change a project's HEAD.
+
+== SYNOPSIS
+--
+'ssh' -p <port> <host> 'gerrit set-head'
+  --project <NAME> | -p <NAME>
+  --new-head <REF>
+--
+
+== DESCRIPTION
+Modifies a given project's HEAD reference.
+
+The command is argument-safe, that is, if no argument is given the
+previous settings are kept intact.
+
+== ACCESS
+Caller must be an owner of the given project.
+
+== SCRIPTING
+This command is intended to be used in scripts.
+
+== OPTIONS
+<PROJECT_NAME>::
+    Required; name of the project to change the HEAD. If name ends
+    with `.git` the suffix will be automatically removed.
+
+--new-head::
+    Required; name of the ref that should be set as new HEAD. The
+    'refs/heads/' prefix can be omitted.
+
+== EXAMPLES
+Change HEAD of project `example` to `stable-2.11` branch:
+
+====
+    $ ssh -p 29418 review.example.com gerrit set-head example --new-head stable-2.11
+====
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
index 77c221c..ac21646 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/SetHead.java
@@ -43,9 +43,9 @@
 public class SetHead implements RestModifyView<ProjectResource, Input> {
   private static final Logger log = LoggerFactory.getLogger(SetHead.class);
 
-  static class Input {
+  public static class Input {
     @DefaultInput
-    String ref;
+    public String ref;
   }
 
   private final GitRepositoryManager repoManager;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
index f75eb2b..01d40f7 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/DefaultCommandModule.java
@@ -77,6 +77,7 @@
     command(gerrit, CreateAccountCommand.class);
     command(gerrit, CreateGroupCommand.class);
     command(gerrit, CreateProjectCommand.class);
+    command(gerrit, SetHeadCommand.class);
     command(gerrit, AdminQueryShell.class);
     if (!slaveMode) {
       command("git-receive-pack").to(Commands.key(git, "receive-pack"));
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetHeadCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetHeadCommand.java
new file mode 100644
index 0000000..b1d1605
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/SetHeadCommand.java
@@ -0,0 +1,55 @@
+// Copyright (C) 2015 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.restapi.UnprocessableEntityException;
+import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.project.ProjectResource;
+import com.google.gerrit.server.project.SetHead;
+import com.google.gerrit.server.project.SetHead.Input;
+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;
+
+@CommandMetaData(name = "set-head", description = "Change HEAD reference for a project")
+public class SetHeadCommand extends SshCommand {
+
+  @Argument(index = 0, required = true, metaVar = "NAME", usage = "name of the project")
+  private ProjectControl project;
+
+  @Option(name = "--new-head", required = true, metaVar = "REF", usage = "new HEAD reference")
+  private String newHead;
+
+  private final SetHead setHead;
+
+  @Inject
+  SetHeadCommand(SetHead setHead) {
+    this.setHead = setHead;
+  }
+
+  @Override
+  protected void run() throws Exception {
+    Input input = new SetHead.Input();
+    input.ref = newHead;
+    try {
+      setHead.apply(new ProjectResource(project), input);
+    } catch (UnprocessableEntityException e) {
+      throw new UnloggedFailure("fatal: " + e.getMessage());
+    }
+  }
+}