Merge "Add new SSH command to rename groups"
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index 64c42a0..a6296b4 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -57,6 +57,9 @@
link:cmd-ls-projects.html[gerrit ls-projects]::
List projects visible to the caller.
+link:cmd-ls-projects.html[gerrit rename-group]::
+ Rename an account group.
+
link:cmd-set-reviewers.html[gerrit set-reviewers]::
Add or remove reviewers on a change.
diff --git a/Documentation/cmd-rename-group.txt b/Documentation/cmd-rename-group.txt
new file mode 100644
index 0000000..e810727
--- /dev/null
+++ b/Documentation/cmd-rename-group.txt
@@ -0,0 +1,46 @@
+gerrit rename-group
+===================
+
+NAME
+----
+gerrit rename-group - Rename an account group.
+
+SYNOPSIS
+--------
+[verse]
+'ssh' -p <port> <host> 'gerrit rename-group'
+ <GROUP>
+ <NEWNAME>
+
+DESCRIPTION
+-----------
+Renames an account group.
+
+ACCESS
+------
+Caller must be a member of the group owning the group to be renamed
+or be a member of the privileged 'Administrators' group.
+
+SCRIPTING
+---------
+This command is intended to be used in scripts.
+
+OPTIONS
+-------
+<GROUP>::
+ Required; name of the group to be renamed.
+
+<NEWNAME>::
+ Required; new name of the group.
+
+EXAMPLES
+--------
+Rename the group "MyGroup" to "MyCommitters".
+
+====
+ $ ssh -p 29418 user@review.example.com gerrit rename-group MyGroup MyCommitters
+====
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
index d7cd195..2d7770e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/account/RenameGroup.java
@@ -19,51 +19,25 @@
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.AccountGroup;
-import com.google.gerrit.reviewdb.AccountGroupName;
-import com.google.gerrit.reviewdb.ReviewDb;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.account.GroupCache;
-import com.google.gerrit.server.account.GroupControl;
-import com.google.gerrit.server.account.GroupDetailFactory;
-import com.google.gerrit.server.git.RenameGroupOp;
-import com.google.gwtorm.client.OrmDuplicateKeyException;
+import com.google.gerrit.server.account.PerformRenameGroup;
import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
-import java.util.Collections;
-import java.util.Date;
-import java.util.TimeZone;
-import java.util.concurrent.TimeUnit;
-
class RenameGroup extends Handler<GroupDetail> {
interface Factory {
RenameGroup create(AccountGroup.Id id, String newName);
}
- private final ReviewDb db;
- private final GroupCache groupCache;
- private final GroupControl.Factory groupControlFactory;
- private final GroupDetailFactory.Factory groupDetailFactory;
- private final RenameGroupOp.Factory renameGroupOpFactory;
- private final IdentifiedUser currentUser;
+ private final PerformRenameGroup.Factory performRenameGroupFactory;
private final AccountGroup.Id groupId;
private final String newName;
@Inject
- RenameGroup(final ReviewDb db, final GroupCache groupCache,
- final GroupControl.Factory groupControlFactory,
- final GroupDetailFactory.Factory groupDetailFactory,
- final RenameGroupOp.Factory renameGroupOpFactory,
- final IdentifiedUser currentUser,
+ RenameGroup(final PerformRenameGroup.Factory performRenameGroupFactory,
@Assisted final AccountGroup.Id groupId, @Assisted final String newName) {
- this.db = db;
- this.groupCache = groupCache;
- this.groupControlFactory = groupControlFactory;
- this.groupDetailFactory = groupDetailFactory;
- this.renameGroupOpFactory = renameGroupOpFactory;
- this.currentUser = currentUser;
+ this.performRenameGroupFactory = performRenameGroupFactory;
this.groupId = groupId;
this.newName = newName;
}
@@ -71,46 +45,6 @@
@Override
public GroupDetail call() throws OrmException, NameAlreadyUsedException,
NoSuchGroupException {
- final GroupControl ctl = groupControlFactory.validateFor(groupId);
- final AccountGroup group = db.accountGroups().get(groupId);
- if (group == null || !ctl.isOwner()) {
- throw new NoSuchGroupException(groupId);
- }
-
- final AccountGroup.NameKey old = group.getNameKey();
- final AccountGroup.NameKey key = new AccountGroup.NameKey(newName);
-
- try {
- final AccountGroupName id = new AccountGroupName(key, groupId);
- db.accountGroupNames().insert(Collections.singleton(id));
- } catch (OrmDuplicateKeyException dupeErr) {
- // If we are using this identity, don't report the exception.
- //
- AccountGroupName other = db.accountGroupNames().get(key);
- if (other != null && other.getId().equals(groupId)) {
- return groupDetailFactory.create(groupId).call();
- }
-
- // Otherwise, someone else has this identity.
- //
- throw new NameAlreadyUsedException();
- }
-
- group.setNameKey(key);
- db.accountGroups().update(Collections.singleton(group));
-
- AccountGroupName priorName = db.accountGroupNames().get(old);
- if (priorName != null) {
- db.accountGroupNames().delete(Collections.singleton(priorName));
- }
-
- groupCache.evict(group);
- groupCache.evictAfterRename(old);
- renameGroupOpFactory.create( //
- currentUser.newCommitterIdent(new Date(), TimeZone.getDefault()), //
- group.getGroupUUID(), //
- old.get(), newName).start(0, TimeUnit.MILLISECONDS);
-
- return groupDetailFactory.create(groupId).call();
+ return performRenameGroupFactory.create().renameGroup(groupId, newName);
}
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
new file mode 100644
index 0000000..92f5fbf
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/PerformRenameGroup.java
@@ -0,0 +1,118 @@
+// Copyright (C) 2011 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.server.account;
+
+import com.google.gerrit.common.data.GroupDetail;
+import com.google.gerrit.common.errors.NameAlreadyUsedException;
+import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.AccountGroupName;
+import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.git.RenameGroupOp;
+import com.google.gwtorm.client.OrmDuplicateKeyException;
+import com.google.gwtorm.client.OrmException;
+import com.google.inject.Inject;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
+public class PerformRenameGroup {
+
+ public interface Factory {
+ PerformRenameGroup create();
+ }
+
+ private final ReviewDb db;
+ private final GroupCache groupCache;
+ private final GroupControl.Factory groupControlFactory;
+ private final GroupDetailFactory.Factory groupDetailFactory;
+ private final RenameGroupOp.Factory renameGroupOpFactory;
+ private final IdentifiedUser currentUser;
+
+ @Inject
+ PerformRenameGroup(final ReviewDb db, final GroupCache groupCache,
+ final GroupControl.Factory groupControlFactory,
+ final GroupDetailFactory.Factory groupDetailFactory,
+ final RenameGroupOp.Factory renameGroupOpFactory,
+ final IdentifiedUser currentUser) {
+ this.db = db;
+ this.groupCache = groupCache;
+ this.groupControlFactory = groupControlFactory;
+ this.groupDetailFactory = groupDetailFactory;
+ this.renameGroupOpFactory = renameGroupOpFactory;
+ this.currentUser = currentUser;
+ }
+
+ public GroupDetail renameGroup(final String groupName,
+ final String newGroupName) throws OrmException, NameAlreadyUsedException,
+ NoSuchGroupException {
+ final AccountGroup.NameKey groupNameKey =
+ new AccountGroup.NameKey(groupName);
+ final AccountGroup group = groupCache.get(groupNameKey);
+ if (group == null) {
+ throw new NoSuchGroupException(groupNameKey);
+ }
+ return renameGroup(group.getId(), newGroupName);
+ }
+
+ public GroupDetail renameGroup(final AccountGroup.Id groupId,
+ final String newName) throws OrmException, NameAlreadyUsedException,
+ NoSuchGroupException {
+ final GroupControl ctl = groupControlFactory.validateFor(groupId);
+ final AccountGroup group = db.accountGroups().get(groupId);
+ if (group == null || !ctl.isOwner()) {
+ throw new NoSuchGroupException(groupId);
+ }
+
+ final AccountGroup.NameKey old = group.getNameKey();
+ final AccountGroup.NameKey key = new AccountGroup.NameKey(newName);
+
+ try {
+ final AccountGroupName id = new AccountGroupName(key, groupId);
+ db.accountGroupNames().insert(Collections.singleton(id));
+ } catch (OrmDuplicateKeyException dupeErr) {
+ // If we are using this identity, don't report the exception.
+ //
+ AccountGroupName other = db.accountGroupNames().get(key);
+ if (other != null && other.getId().equals(groupId)) {
+ return groupDetailFactory.create(groupId).call();
+ }
+
+ // Otherwise, someone else has this identity.
+ //
+ throw new NameAlreadyUsedException();
+ }
+
+ group.setNameKey(key);
+ db.accountGroups().update(Collections.singleton(group));
+
+ AccountGroupName priorName = db.accountGroupNames().get(old);
+ if (priorName != null) {
+ db.accountGroupNames().delete(Collections.singleton(priorName));
+ }
+
+ groupCache.evict(group);
+ groupCache.evictAfterRename(old);
+ renameGroupOpFactory.create( //
+ currentUser.newCommitterIdent(new Date(), TimeZone.getDefault()), //
+ group.getGroupUUID(), //
+ old.get(), newName).start(0, TimeUnit.MILLISECONDS);
+
+ return groupDetailFactory.create(groupId).call();
+ }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
index 3ba9aab..42c2531 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritRequestModule.java
@@ -25,6 +25,7 @@
import com.google.gerrit.server.account.GroupDetailFactory;
import com.google.gerrit.server.account.GroupMembersFactory;
import com.google.gerrit.server.account.PerformCreateGroup;
+import com.google.gerrit.server.account.PerformRenameGroup;
import com.google.gerrit.server.git.CreateCodeReviewNotes;
import com.google.gerrit.server.git.MergeOp;
import com.google.gerrit.server.git.MetaDataUpdate;
@@ -89,6 +90,7 @@
factory(MergeFailSender.Factory.class);
factory(RegisterNewEmailSender.Factory.class);
factory(PerformCreateGroup.Factory.class);
+ factory(PerformRenameGroup.Factory.class);
factory(GroupDetailFactory.Factory.class);
factory(GroupMembersFactory.Factory.class);
}
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 6a69791..da04196 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
@@ -28,6 +28,7 @@
command(gerrit, "approve").to(ReviewCommand.class);
command(gerrit, "create-account").to(CreateAccountCommand.class);
command(gerrit, "create-group").to(CreateGroupCommand.class);
+ command(gerrit, "rename-group").to(RenameGroupCommand.class);
command(gerrit, "create-project").to(CreateProject.class);
command(gerrit, "gsql").to(AdminQueryShell.class);
command(gerrit, "set-reviewers").to(SetReviewersCommand.class);
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
new file mode 100644
index 0000000..b6d5bf5
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/RenameGroupCommand.java
@@ -0,0 +1,58 @@
+// Copyright (C) 2011 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.common.errors.NameAlreadyUsedException;
+import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.server.account.PerformRenameGroup;
+import com.google.gerrit.sshd.BaseCommand;
+import com.google.gwtorm.client.OrmException;
+import com.google.inject.Inject;
+
+import org.apache.sshd.server.Environment;
+import org.kohsuke.args4j.Argument;
+
+import java.io.IOException;
+
+public class RenameGroupCommand extends BaseCommand {
+
+ @Argument(index = 0, required = true, metaVar = "GROUP", usage = "name of the group to be renamed")
+ private String groupName;
+
+ @Argument(index = 1, required = true, metaVar = "NEWNAME", usage = "new name of the group")
+ private String newGroupName;
+
+ @Inject
+ private PerformRenameGroup.Factory performRenameGroupFactory;
+
+ @Override
+ public void start(final Environment env) throws IOException {
+ startThread(new CommandRunnable() {
+ @Override
+ public void run() throws Exception {
+ parseCommandLine();
+ try {
+ performRenameGroupFactory.create().renameGroup(groupName, newGroupName);
+ } catch (OrmException e) {
+ throw die(e);
+ } catch (NameAlreadyUsedException e) {
+ throw die(e);
+ } catch (NoSuchGroupException e) {
+ throw die(e);
+ }
+ }
+ });
+ }
+}