summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSasa Zivkov <sasa.zivkov@sap.com>2010-07-30 15:13:58 +0200
committerSasa Zivkov <sasa.zivkov@sap.com>2010-07-30 16:41:08 +0200
commit71963a5e0e578a8b7b8f1de67c2bb58da3f46b56 (patch)
treeea34d558c8c6c19942c389fa1631688d948dcb78
parent086b7196e71b29edbb37bff93035e633e8fd752d (diff)
Implemented ssh command create-group
Often, when creating a new gerrit project a gerrit admin needs to create a new project owner group and setup an initial set of group members. This was only possible from gerrit's Web UI and was a realtively slow process compared to the easiness of creating the project using the create-project ssh command. This command makes it possible to create a new group, assign group members, owner group and description via ssh. Bug: issue 313 Change-Id: I9fbc013bd5e596f0b23e411ee0cc72d5f67b5f39 Signed-off-by: Sasa Zivkov <sasa.zivkov@sap.com>
-rw-r--r--Documentation/cmd-create-group.txt76
-rw-r--r--Documentation/cmd-index.txt3
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java20
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java4
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateAccount.java4
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateGroup.java115
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/MasterCommandModule.java1
7 files changed, 216 insertions, 7 deletions
diff --git a/Documentation/cmd-create-group.txt b/Documentation/cmd-create-group.txt
new file mode 100644
index 0000000000..d5bc7578ee
--- /dev/null
+++ b/Documentation/cmd-create-group.txt
@@ -0,0 +1,76 @@
+gerrit create-group
+===================
+
+NAME
+----
+gerrit create-group - Create a new account group.
+
+SYNOPSIS
+--------
+[verse]
+'ssh' -p <port> <host> 'gerrit create-group' \
+[\--owner <GROUP>] \
+[\--description <DESC>] \
+[\--member <USERNAME>] \
+<GROUP>
+
+DESCRIPTION
+-----------
+Creates a new account group. The group creating user (the user that
+fired the create-group command) is not automatically added to
+the created group. In case the creating user wants to be a member of
+the group he/she must list itself in the --member option. This is
+slightly different from Gerrit's Web UI where the creating user automatically
+becomes a member of the newly created group.
+
+ACCESS
+------
+Caller must be a member of the privileged 'Administrators' group.
+
+SCRIPTING
+---------
+This command is intended to be used in scripts.
+
+OPTIONS
+-------
+<GROUP>::
+ Required; name of the new group.
+
+\--owner, -o::
+ Name of the owning group. If not specified the group will be self-owning.
+
+\--description, -d::
+ Description of group.
++
+Description values containing spaces should be quoted in single quotes
+(\'). This most likely requires double quoting the value, for example
+`\--description "\'A description string\'"`.
+
+\--member::
+ User name to become initial member of the group. Multiple \--member
+ options may be specified to add more initial members.
+
+EXAMPLES
+--------
+Create a new account group called `gerritdev` with two initial members
+`developer1` and `developer2`. The group should be owned by itself:
+
+====
+ $ ssh -p 29418 user@review.example.com gerrit create-group --member developer1 --member developer2 gerritdev
+====
+
+Create a new account group called `Foo` owned by the `Foo-admin` group.
+Put `developer1` as the initial member and include group description:
+
+====
+ $ ssh -p 29418 user@review.example.com gerrit create-group --owner Foo-admin --member developer1 --description "'Foo description'" Foo
+====
+
+Note that it is necessary to quote the description twice. The local
+shell needs double quotes around the value to ensure the single quotes
+are passed through SSH as-is to the remote Gerrit server, which uses
+the single quotes to delimit the value.
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/cmd-index.txt b/Documentation/cmd-index.txt
index e213222048..79557d3266 100644
--- a/Documentation/cmd-index.txt
+++ b/Documentation/cmd-index.txt
@@ -84,6 +84,9 @@ gerrit receive-pack::
link:cmd-create-account.html[gerrit create-account]::
Create a new batch/role account.
+link:cmd-create-group.html[gerrit create-group]::
+ Create a new account group.
+
link:cmd-create-project.html[gerrit create-project]::
Create a new project and associated Git repository.
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
index 7bfd58570c..3200dd9ce5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountResolver.java
@@ -46,8 +46,8 @@ public class AccountResolver {
*
* @param nameOrEmail a string of the format
* "Full Name &lt;email@example&gt;", just the email address
- * ("email@example"), a full name ("Full Name"), or an account id
- * ("18419").
+ * ("email@example"), a full name ("Full Name"), an account id
+ * ("18419") or an user name ("username").
* @return the single account that matches; null if no account matches or
* there are multiple candidates.
*/
@@ -61,7 +61,16 @@ public class AccountResolver {
return byId.get(Account.Id.parse(nameOrEmail)).getAccount();
}
- return findByNameOrEmail(nameOrEmail);
+ Account account = findByNameOrEmail(nameOrEmail);
+ if (account != null) {
+ return account;
+ }
+
+ if (nameOrEmail.matches(Account.USER_NAME_PATTERN)) {
+ return findByUserName(nameOrEmail);
+ }
+
+ return null;
}
/**
@@ -105,4 +114,9 @@ public class AccountResolver {
final List<Account> r = rs.toList();
return r.size() == 1 ? r.get(0) : null;
}
+
+ private Account findByUserName(final String userName) throws OrmException {
+ AccountState as = byId.getByUsername(userName);
+ return as != null ? as.getAccount() : null;
+ }
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
index f46b3ec784..9b155dba5b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
@@ -343,6 +343,10 @@ public abstract class BaseCommand implements Command {
}
}
+ protected UnloggedFailure die(String msg) {
+ return new UnloggedFailure(1, "fatal: " + msg);
+ }
+
private final class TaskThunk implements CancelableRunnable, ProjectRunnable {
private final CommandRunnable thunk;
private final Context context;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateAccount.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateAccount.java
index 48194f9902..06e92ca8ac 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateAccount.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateAccount.java
@@ -152,10 +152,6 @@ final class AdminCreateAccount extends BaseCommand {
byEmailCache.evict(email);
}
- private UnloggedFailure die(String msg) {
- return new UnloggedFailure(1, "fatal: " + msg);
- }
-
private AccountExternalId.Key getEmailKey() {
return new AccountExternalId.Key(AccountExternalId.SCHEME_MAILTO, email);
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateGroup.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateGroup.java
new file mode 100644
index 0000000000..d99d8482ef
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminCreateGroup.java
@@ -0,0 +1,115 @@
+// Copyright (C) 2010 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.reviewdb.Account;
+import com.google.gerrit.reviewdb.AccountGroup;
+import com.google.gerrit.reviewdb.AccountGroupMember;
+import com.google.gerrit.reviewdb.AccountGroupMemberAudit;
+import com.google.gerrit.reviewdb.AccountGroupName;
+import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.sshd.AdminCommand;
+import com.google.gerrit.sshd.BaseCommand;
+import com.google.gwtorm.client.OrmDuplicateKeyException;
+import com.google.gwtorm.client.OrmException;
+import com.google.inject.Inject;
+
+import org.apache.sshd.server.Environment;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Creates a new group.
+ * <p>
+ * Optionally, puts an initial set of user in the newly created group.
+ */
+@AdminCommand
+public class AdminCreateGroup extends BaseCommand {
+ @Option(name = "--owner", aliases = {"-o"}, metaVar = "GROUP", usage = "owning group, if not specified the group will be self-owning")
+ private AccountGroup.Id ownerGroupId;
+
+ @Option(name = "--description", aliases = {"-d"}, metaVar = "DESC", usage = "description of group")
+ private String groupDescription = "";
+
+ @Argument(index = 0, required = true, metaVar = "GROUP", usage = "name of group to be created")
+ private String groupName;
+
+ @Inject
+ private IdentifiedUser currentUser;
+
+ @Inject
+ private ReviewDb db;
+
+ private final Set<Account.Id> initialMembers = new HashSet<Account.Id>();
+
+ @Option(name = "--member", aliases = {"-m"}, metaVar = "USERNAME", usage = "initial set of users to become members of the group")
+ void addMember(final Account.Id id) {
+ initialMembers.add(id);
+ }
+
+ @Override
+ public void start(Environment env) throws IOException {
+ startThread(new CommandRunnable() {
+ @Override
+ public void run() throws Exception {
+ parseCommandLine();
+ createGroup();
+ }
+ });
+ }
+
+ private void createGroup() throws OrmException, UnloggedFailure {
+ AccountGroup.Id groupId = new AccountGroup.Id(db.nextAccountGroupId());
+ AccountGroup.NameKey nameKey = new AccountGroup.NameKey(groupName);
+ AccountGroup group = new AccountGroup(nameKey, groupId);
+ if (ownerGroupId != null) {
+ group.setOwnerGroupId(ownerGroupId);
+ }
+ if (groupDescription != null) {
+ group.setDescription(groupDescription);
+ }
+ AccountGroupName gn = new AccountGroupName(group);
+ // first insert the group name to validate that the group name hasn't already been
+ // used to create another group
+ try {
+ db.accountGroupNames().insert(Collections.singleton(gn));
+ } catch (OrmDuplicateKeyException e) {
+ throw die("group '" + groupName + "' already exists");
+ }
+ db.accountGroups().insert(Collections.singleton(group));
+
+ List<AccountGroupMember> memberships = new ArrayList<AccountGroupMember>();
+ List<AccountGroupMemberAudit> membershipsAudit = new ArrayList<AccountGroupMemberAudit>();
+ for (Account.Id accountId : initialMembers) {
+ AccountGroupMember membership =
+ new AccountGroupMember(new AccountGroupMember.Key(accountId, groupId));
+ memberships.add(membership);
+
+ AccountGroupMemberAudit audit =
+ new AccountGroupMemberAudit(membership, currentUser.getAccountId());
+ membershipsAudit.add(audit);
+ }
+ db.accountGroupMembers().insert(memberships);
+ db.accountGroupMembersAudit().insert(membershipsAudit);
+ }
+} \ No newline at end of file
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 c83d604e34..466d454da3 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
@@ -27,6 +27,7 @@ public class MasterCommandModule extends CommandModule {
command(gerrit, "approve").to(ReviewCommand.class);
command(gerrit, "create-account").to(AdminCreateAccount.class);
+ command(gerrit, "create-group").to(AdminCreateGroup.class);
command(gerrit, "create-project").to(CreateProject.class);
command(gerrit, "gsql").to(AdminQueryShell.class);
command(gerrit, "receive-pack").to(Receive.class);