diff options
author | Shawn Pearce <sop@google.com> | 2010-07-30 09:09:04 -0700 |
---|---|---|
committer | Android Code Review <code-review@android.com> | 2010-07-30 09:09:04 -0700 |
commit | 75394db8515f28c614d8196d7dab08b4775f3975 (patch) | |
tree | 9e814a21898fe98da9c4b55e7bf4372af4548565 | |
parent | 4a4b86e392ad9800cafc883008afceb11df0e01d (diff) | |
parent | 71963a5e0e578a8b7b8f1de67c2bb58da3f46b56 (diff) |
Merge "Implemented ssh command create-group"
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 <email@example>", 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); |