Merge "Implemented ssh command create-group"
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]::
 | 
			
		||||
	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.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -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, "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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user