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>
This commit is contained in:
76
Documentation/cmd-create-group.txt
Normal file
76
Documentation/cmd-create-group.txt
Normal file
@@ -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]
|
||||||
@@ -84,6 +84,9 @@ gerrit receive-pack::
|
|||||||
link:cmd-create-account.html[gerrit create-account]::
|
link:cmd-create-account.html[gerrit create-account]::
|
||||||
Create a new batch/role 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]::
|
link:cmd-create-project.html[gerrit create-project]::
|
||||||
Create a new project and associated Git repository.
|
Create a new project and associated Git repository.
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ public class AccountResolver {
|
|||||||
*
|
*
|
||||||
* @param nameOrEmail a string of the format
|
* @param nameOrEmail a string of the format
|
||||||
* "Full Name <email@example>", just the email address
|
* "Full Name <email@example>", just the email address
|
||||||
* ("email@example"), a full name ("Full Name"), or an account id
|
* ("email@example"), a full name ("Full Name"), an account id
|
||||||
* ("18419").
|
* ("18419") or an user name ("username").
|
||||||
* @return the single account that matches; null if no account matches or
|
* @return the single account that matches; null if no account matches or
|
||||||
* there are multiple candidates.
|
* there are multiple candidates.
|
||||||
*/
|
*/
|
||||||
@@ -61,7 +61,16 @@ public class AccountResolver {
|
|||||||
return byId.get(Account.Id.parse(nameOrEmail)).getAccount();
|
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();
|
final List<Account> r = rs.toList();
|
||||||
return r.size() == 1 ? r.get(0) : null;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 class TaskThunk implements CancelableRunnable, ProjectRunnable {
|
||||||
private final CommandRunnable thunk;
|
private final CommandRunnable thunk;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|||||||
@@ -152,10 +152,6 @@ final class AdminCreateAccount extends BaseCommand {
|
|||||||
byEmailCache.evict(email);
|
byEmailCache.evict(email);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnloggedFailure die(String msg) {
|
|
||||||
return new UnloggedFailure(1, "fatal: " + msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AccountExternalId.Key getEmailKey() {
|
private AccountExternalId.Key getEmailKey() {
|
||||||
return new AccountExternalId.Key(AccountExternalId.SCHEME_MAILTO, email);
|
return new AccountExternalId.Key(AccountExternalId.SCHEME_MAILTO, email);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ public class MasterCommandModule extends CommandModule {
|
|||||||
|
|
||||||
command(gerrit, "approve").to(ReviewCommand.class);
|
command(gerrit, "approve").to(ReviewCommand.class);
|
||||||
command(gerrit, "create-account").to(AdminCreateAccount.class);
|
command(gerrit, "create-account").to(AdminCreateAccount.class);
|
||||||
|
command(gerrit, "create-group").to(AdminCreateGroup.class);
|
||||||
command(gerrit, "create-project").to(CreateProject.class);
|
command(gerrit, "create-project").to(CreateProject.class);
|
||||||
command(gerrit, "gsql").to(AdminQueryShell.class);
|
command(gerrit, "gsql").to(AdminQueryShell.class);
|
||||||
command(gerrit, "receive-pack").to(Receive.class);
|
command(gerrit, "receive-pack").to(Receive.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user