Enable create-project for non-Administrators
Allow other than 'Administrators' to use the create-project command. Added configuration parameters in gerrit.config to denote which group(s) are allowed to create projects, and which group(s) should be new projects' owner(s) by default. repository.*.createGroup specifies which group(s) are allowed to create projects. Default is 'Administrators'. repository.*.ownerGroup specifies which group(s) become the owner(s) of new projects. Default is whatever is specified by repository.*.createGroup, or 'Administrators' if no such configuration exists. Can be overridden by create-project's parameter --owner. Bug: issue 269 Change-Id: Ieeb694508dd4c12578877335a63944bc90d6b553
This commit is contained in:
parent
c025627422
commit
072b470570
@ -11,7 +11,7 @@ SYNOPSIS
|
|||||||
'ssh' -p <port> <host> 'gerrit create-project' \
|
'ssh' -p <port> <host> 'gerrit create-project' \
|
||||||
\--name <NAME> \
|
\--name <NAME> \
|
||||||
[--branch <REF>] \
|
[--branch <REF>] \
|
||||||
[\--owner <GROUP>] \
|
[\--owner <GROUP> ...] \
|
||||||
[\--description <DESC>] \
|
[\--description <DESC>] \
|
||||||
[\--submit-type <TYPE>] \
|
[\--submit-type <TYPE>] \
|
||||||
[\--use-contributor-agreements] \
|
[\--use-contributor-agreements] \
|
||||||
@ -32,7 +32,11 @@ on the remote system to create the empty repository.
|
|||||||
|
|
||||||
ACCESS
|
ACCESS
|
||||||
------
|
------
|
||||||
Caller must be a member of the privileged 'Administrators' group.
|
Caller must be a member of any of the groups defined by
|
||||||
|
repository.*.createGroup in gerrit.config.
|
||||||
|
|
||||||
|
If there is no such declaration, caller is required to be a member
|
||||||
|
of the privileged 'Administrators' group.
|
||||||
|
|
||||||
SCRIPTING
|
SCRIPTING
|
||||||
---------
|
---------
|
||||||
@ -49,13 +53,14 @@ OPTIONS
|
|||||||
Defaults to 'master'.
|
Defaults to 'master'.
|
||||||
|
|
||||||
\--owner::
|
\--owner::
|
||||||
Name of the group which will initially own this repository.
|
Name of the group(s) which will initially own this repository.
|
||||||
The specified group must already be defined within Gerrit.
|
The specified group(s) must already be defined within Gerrit.
|
||||||
Only one group can be specified on the command line.
|
Several groups can be specified on the command line.
|
||||||
To specify additional owners, add the additional owners
|
|
||||||
through the web interface after project creation.
|
|
||||||
+
|
+
|
||||||
Defaults to `Administrators` if not specified.
|
Defaults to what is specified by repository.*.ownerGroup
|
||||||
|
in gerrit.config. If no such declaration(s) exist,
|
||||||
|
repository.*.createGroup will be used. If they don't exist,
|
||||||
|
`Administrators` will be used.
|
||||||
|
|
||||||
\--description::
|
\--description::
|
||||||
Initial description of the project. If not specified,
|
Initial description of the project. If not specified,
|
||||||
|
@ -1235,6 +1235,45 @@ instance are generally worked on with the repo multi-repository tool.
|
|||||||
+
|
+
|
||||||
By default, false, as not all instances will deploy repo.
|
By default, false, as not all instances will deploy repo.
|
||||||
|
|
||||||
|
[[repository]]Section repository
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Repositories in this sense are the same as projects.
|
||||||
|
|
||||||
|
In the following example configuration the `Administrators` and the
|
||||||
|
`Registered Users` groups are set to be the ones to be allowed to
|
||||||
|
create projects matching `*` (any project). `Registered Users` is
|
||||||
|
set to be the default owner of new projects.
|
||||||
|
|
||||||
|
----
|
||||||
|
[repository "*"]
|
||||||
|
createGroup = Administrators
|
||||||
|
createGroup = Registered Users
|
||||||
|
ownerGroup = Registered Users
|
||||||
|
----
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
Currently only the repository name `*` is supported.
|
||||||
|
This is a wildcard designating all repositories.
|
||||||
|
|
||||||
|
[[repository.name.createGroup]]repository.<name>.createGroup::
|
||||||
|
+
|
||||||
|
A name of a group which exists in the database. Zero, one or many
|
||||||
|
groups are allowed. Each on its own line. Groups which don't exist
|
||||||
|
in the database are ignored.
|
||||||
|
+
|
||||||
|
If no groups are declared (or only non-existing ones), the default
|
||||||
|
value `Administrators` is used.
|
||||||
|
|
||||||
|
[[repository.name.ownerGroup]]repository.<name>.ownerGroup::
|
||||||
|
+
|
||||||
|
A name of a group which exists in the database. Zero, one or many
|
||||||
|
groups are allowed. Each on its own line. Groups which don't exist
|
||||||
|
in the database are ignored.
|
||||||
|
+
|
||||||
|
If no groups are declared (or only non-existing ones), it defaults
|
||||||
|
to whatever is declared by `repository.<name>.createGroup` (including
|
||||||
|
any fallback to `Administrators`.)
|
||||||
|
|
||||||
[[sendemail]]Section sendemail
|
[[sendemail]]Section sendemail
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -16,9 +16,18 @@ package com.google.gerrit.server.config;
|
|||||||
|
|
||||||
import static org.eclipse.jgit.util.StringUtils.equalsIgnoreCase;
|
import static org.eclipse.jgit.util.StringUtils.equalsIgnoreCase;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.AccountGroup;
|
||||||
|
import com.google.gerrit.reviewdb.AccountGroupName;
|
||||||
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
|
import com.google.gwtorm.client.OrmException;
|
||||||
|
import com.google.gwtorm.client.SchemaFactory;
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class ConfigUtil {
|
public class ConfigUtil {
|
||||||
@ -199,6 +208,60 @@ public class ConfigUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve groups from group names, via the database. Group names not found in
|
||||||
|
* the database will be skipped.
|
||||||
|
*
|
||||||
|
* @param dbfactory database to resolve from.
|
||||||
|
* @param groupNames group names to resolve.
|
||||||
|
* @param log log for any warnings and errors.
|
||||||
|
* @param groupNotFoundWarning formatted message to output to the log for each
|
||||||
|
* group name which is not found in the database. <code>{0}</code> will
|
||||||
|
* be replaced with the group name.
|
||||||
|
* @return the actual groups resolved from the database. If no groups are
|
||||||
|
* found, returns an empty {@code Set}, never {@code null}.
|
||||||
|
*/
|
||||||
|
public static Set<AccountGroup.Id> groupsFor(
|
||||||
|
SchemaFactory<ReviewDb> dbfactory, String[] groupNames, Logger log,
|
||||||
|
String groupNotFoundWarning) {
|
||||||
|
final Set<AccountGroup.Id> result = new HashSet<AccountGroup.Id>();
|
||||||
|
try {
|
||||||
|
final ReviewDb db = dbfactory.open();
|
||||||
|
try {
|
||||||
|
for (String name : groupNames) {
|
||||||
|
AccountGroupName group =
|
||||||
|
db.accountGroupNames().get(new AccountGroup.NameKey(name));
|
||||||
|
if (group == null) {
|
||||||
|
log.warn(MessageFormat.format(groupNotFoundWarning, name));
|
||||||
|
} else {
|
||||||
|
result.add(group.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
} catch (OrmException e) {
|
||||||
|
log.error("Database error, cannot load groups", e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve groups from group names, via the database. Group names not found in
|
||||||
|
* the database will be skipped.
|
||||||
|
*
|
||||||
|
* @param dbfactory database to resolve from.
|
||||||
|
* @param groupNames group names to resolve.
|
||||||
|
* @param log log for any warnings and errors.
|
||||||
|
* @return the actual groups resolved from the database. If no groups are
|
||||||
|
* found, returns an empty {@code Set}, never {@code null}.
|
||||||
|
*/
|
||||||
|
public static Set<AccountGroup.Id> groupsFor(
|
||||||
|
SchemaFactory<ReviewDb> dbfactory, String[] groupNames, Logger log) {
|
||||||
|
return groupsFor(dbfactory, groupNames, log,
|
||||||
|
"Group \"{0}\" not in database, skipping.");
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean match(final String a, final String... cases) {
|
private static boolean match(final String a, final String... cases) {
|
||||||
for (final String b : cases) {
|
for (final String b : cases) {
|
||||||
if (equalsIgnoreCase(a, b)) {
|
if (equalsIgnoreCase(a, b)) {
|
||||||
|
@ -18,6 +18,7 @@ import static com.google.inject.Scopes.SINGLETON;
|
|||||||
|
|
||||||
import com.google.gerrit.common.data.ApprovalTypes;
|
import com.google.gerrit.common.data.ApprovalTypes;
|
||||||
import com.google.gerrit.lifecycle.LifecycleModule;
|
import com.google.gerrit.lifecycle.LifecycleModule;
|
||||||
|
import com.google.gerrit.reviewdb.AccountGroup;
|
||||||
import com.google.gerrit.reviewdb.AuthType;
|
import com.google.gerrit.reviewdb.AuthType;
|
||||||
import com.google.gerrit.reviewdb.Project;
|
import com.google.gerrit.reviewdb.Project;
|
||||||
import com.google.gerrit.server.AnonymousUser;
|
import com.google.gerrit.server.AnonymousUser;
|
||||||
@ -64,9 +65,12 @@ import com.google.gerrit.server.util.IdGenerator;
|
|||||||
import com.google.gerrit.server.workflow.FunctionState;
|
import com.google.gerrit.server.workflow.FunctionState;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import com.google.inject.TypeLiteral;
|
||||||
import org.eclipse.jgit.lib.Config;
|
import org.eclipse.jgit.lib.Config;
|
||||||
import org.eclipse.jgit.lib.PersonIdent;
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/** Starts global state with standard dependencies. */
|
/** Starts global state with standard dependencies. */
|
||||||
public class GerritGlobalModule extends FactoryModule {
|
public class GerritGlobalModule extends FactoryModule {
|
||||||
private final AuthType loginType;
|
private final AuthType loginType;
|
||||||
@ -93,6 +97,10 @@ public class GerritGlobalModule extends FactoryModule {
|
|||||||
|
|
||||||
bind(Project.NameKey.class).annotatedWith(WildProjectName.class)
|
bind(Project.NameKey.class).annotatedWith(WildProjectName.class)
|
||||||
.toProvider(WildProjectNameProvider.class).in(SINGLETON);
|
.toProvider(WildProjectNameProvider.class).in(SINGLETON);
|
||||||
|
bind(new TypeLiteral<Set<AccountGroup.Id>>(){}).annotatedWith(ProjectCreatorGroups.class)
|
||||||
|
.toProvider(ProjectCreatorGroupsProvider.class).in(SINGLETON);
|
||||||
|
bind(new TypeLiteral<Set<AccountGroup.Id>>(){}).annotatedWith(ProjectOwnerGroups.class)
|
||||||
|
.toProvider(ProjectOwnerGroupsProvider.class).in(SINGLETON);
|
||||||
bind(ApprovalTypes.class).toProvider(ApprovalTypesProvider.class).in(
|
bind(ApprovalTypes.class).toProvider(ApprovalTypesProvider.class).in(
|
||||||
SINGLETON);
|
SINGLETON);
|
||||||
bind(EmailExpander.class).toProvider(EmailExpanderProvider.class).in(
|
bind(EmailExpander.class).toProvider(EmailExpanderProvider.class).in(
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
// 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.server.config;
|
||||||
|
|
||||||
|
import com.google.inject.BindingAnnotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker on a {@code Set<AccountGroup.Id>} for the configured groups with
|
||||||
|
* permission to create projects.
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@BindingAnnotation
|
||||||
|
public @interface ProjectCreatorGroups {
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
// 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.server.config;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.AccountGroup;
|
||||||
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
|
import com.google.gerrit.reviewdb.SystemConfig;
|
||||||
|
import com.google.gwtorm.client.SchemaFactory;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider of the group(s) which are allowed to create new projects. Currently
|
||||||
|
* only supports {@code createGroup} declarations in the {@code "*"} repository,
|
||||||
|
* like so:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* [repository "*"]
|
||||||
|
* createGroup = Registered Users
|
||||||
|
* createGroup = Administrators
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class ProjectCreatorGroupsProvider implements
|
||||||
|
Provider<Set<AccountGroup.Id>> {
|
||||||
|
private static final Logger log =
|
||||||
|
LoggerFactory.getLogger(ProjectCreatorGroupsProvider.class);
|
||||||
|
|
||||||
|
private final Set<AccountGroup.Id> groupIds;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ProjectCreatorGroupsProvider(@GerritServerConfig final Config config,
|
||||||
|
SchemaFactory<ReviewDb> db, final SystemConfig systemConfig) {
|
||||||
|
String[] names = config.getStringList("repository", "*", "createGroup");
|
||||||
|
Set<AccountGroup.Id> createGroups = ConfigUtil.groupsFor(db, names, log);
|
||||||
|
|
||||||
|
if (createGroups.isEmpty()) {
|
||||||
|
groupIds = Collections.singleton(systemConfig.adminGroupId);
|
||||||
|
} else {
|
||||||
|
groupIds = createGroups;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<AccountGroup.Id> get() {
|
||||||
|
return groupIds;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
// 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.server.config;
|
||||||
|
|
||||||
|
import com.google.inject.BindingAnnotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker on a {@code Set<AccountGroup.Id>} for the configured groups which
|
||||||
|
* should become owners of a created project.
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@BindingAnnotation
|
||||||
|
public @interface ProjectOwnerGroups {
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
// 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.server.config;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.AccountGroup;
|
||||||
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
|
import com.google.gwtorm.client.SchemaFactory;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider of the group(s) which should become owners of a newly created
|
||||||
|
* project. Currently only supports {@code ownerGroup} declarations in the
|
||||||
|
* {@code "*"} repository, like so:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* [repository "*"]
|
||||||
|
* ownerGroup = Registered Users
|
||||||
|
* ownerGroup = Administrators
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class ProjectOwnerGroupsProvider implements
|
||||||
|
Provider<Set<AccountGroup.Id>> {
|
||||||
|
private static final Logger log =
|
||||||
|
LoggerFactory.getLogger(ProjectOwnerGroupsProvider.class);
|
||||||
|
|
||||||
|
private final Set<AccountGroup.Id> groupIds;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ProjectOwnerGroupsProvider(@GerritServerConfig final Config config,
|
||||||
|
SchemaFactory<ReviewDb> db,
|
||||||
|
@ProjectCreatorGroups Set<AccountGroup.Id> creatorGroups) {
|
||||||
|
String[] names = config.getStringList("repository", "*", "ownerGroup");
|
||||||
|
Set<AccountGroup.Id> ownerGroups = ConfigUtil.groupsFor(db, names, log);
|
||||||
|
|
||||||
|
if (ownerGroups.isEmpty()) {
|
||||||
|
groupIds = creatorGroups;
|
||||||
|
} else {
|
||||||
|
groupIds = ownerGroups;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<AccountGroup.Id> get() {
|
||||||
|
return groupIds;
|
||||||
|
}
|
||||||
|
}
|
@ -15,15 +15,14 @@
|
|||||||
package com.google.gerrit.server.git;
|
package com.google.gerrit.server.git;
|
||||||
|
|
||||||
import com.google.gerrit.reviewdb.AccountGroup;
|
import com.google.gerrit.reviewdb.AccountGroup;
|
||||||
import com.google.gerrit.reviewdb.AccountGroupName;
|
|
||||||
import com.google.gerrit.reviewdb.Project;
|
import com.google.gerrit.reviewdb.Project;
|
||||||
import com.google.gerrit.reviewdb.ReviewDb;
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.ReplicationUser;
|
import com.google.gerrit.server.ReplicationUser;
|
||||||
|
import com.google.gerrit.server.config.ConfigUtil;
|
||||||
import com.google.gerrit.server.config.SitePaths;
|
import com.google.gerrit.server.config.SitePaths;
|
||||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||||
import com.google.gerrit.server.project.ProjectControl;
|
import com.google.gerrit.server.project.ProjectControl;
|
||||||
import com.google.gwtorm.client.OrmException;
|
|
||||||
import com.google.gwtorm.client.SchemaFactory;
|
import com.google.gwtorm.client.SchemaFactory;
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@ -55,7 +54,6 @@ import java.net.URISyntaxException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -322,7 +320,8 @@ public class PushReplication implements ReplicationQueue {
|
|||||||
String[] authGroupNames =
|
String[] authGroupNames =
|
||||||
cfg.getStringList("remote", rc.getName(), "authGroup");
|
cfg.getStringList("remote", rc.getName(), "authGroup");
|
||||||
authEnabled = authGroupNames.length > 0;
|
authEnabled = authGroupNames.length > 0;
|
||||||
Set<AccountGroup.Id> authGroups = groupsFor(db, authGroupNames);
|
Set<AccountGroup.Id> authGroups = ConfigUtil.groupsFor(db, authGroupNames, log,
|
||||||
|
"Group \"{0}\" not in database, removing from authGroup");
|
||||||
|
|
||||||
final ReplicationUser remoteUser =
|
final ReplicationUser remoteUser =
|
||||||
replicationUserFactory.create(authGroups);
|
replicationUserFactory.create(authGroups);
|
||||||
@ -347,31 +346,6 @@ public class PushReplication implements ReplicationQueue {
|
|||||||
}).getInstance(PushOp.Factory.class);
|
}).getInstance(PushOp.Factory.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<AccountGroup.Id> groupsFor(
|
|
||||||
SchemaFactory<ReviewDb> dbfactory, String[] groupNames) {
|
|
||||||
final Set<AccountGroup.Id> result = new HashSet<AccountGroup.Id>();
|
|
||||||
try {
|
|
||||||
final ReviewDb db = dbfactory.open();
|
|
||||||
try {
|
|
||||||
for (String name : groupNames) {
|
|
||||||
AccountGroupName group =
|
|
||||||
db.accountGroupNames().get(new AccountGroup.NameKey(name));
|
|
||||||
if (group == null) {
|
|
||||||
log.warn("Group \"" + name + "\" not in database,"
|
|
||||||
+ " removing from authGroup");
|
|
||||||
} else {
|
|
||||||
result.add(group.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
} catch (OrmException e) {
|
|
||||||
log.error("Database error: " + e);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getInt(final RemoteConfig rc, final Config cfg,
|
private int getInt(final RemoteConfig rc, final Config cfg,
|
||||||
final String name, final int defValue) {
|
final String name, final int defValue) {
|
||||||
return cfg.getInt("remote", rc.getName(), name, defValue);
|
return cfg.getInt("remote", rc.getName(), name, defValue);
|
||||||
|
@ -20,10 +20,11 @@ import com.google.gerrit.reviewdb.Project;
|
|||||||
import com.google.gerrit.reviewdb.RefRight;
|
import com.google.gerrit.reviewdb.RefRight;
|
||||||
import com.google.gerrit.reviewdb.ReviewDb;
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
import com.google.gerrit.reviewdb.Project.SubmitType;
|
import com.google.gerrit.reviewdb.Project.SubmitType;
|
||||||
import com.google.gerrit.server.config.AuthConfig;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
|
import com.google.gerrit.server.config.ProjectCreatorGroups;
|
||||||
|
import com.google.gerrit.server.config.ProjectOwnerGroups;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.ReplicationQueue;
|
import com.google.gerrit.server.git.ReplicationQueue;
|
||||||
import com.google.gerrit.sshd.AdminCommand;
|
|
||||||
import com.google.gerrit.sshd.BaseCommand;
|
import com.google.gerrit.sshd.BaseCommand;
|
||||||
import com.google.gwtorm.client.OrmException;
|
import com.google.gwtorm.client.OrmException;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@ -35,17 +36,20 @@ import org.eclipse.jgit.lib.Repository;
|
|||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/** Create a new project. **/
|
/** Create a new project. **/
|
||||||
@AdminCommand
|
final class CreateProject extends BaseCommand {
|
||||||
final class AdminCreateProject extends BaseCommand {
|
|
||||||
@Option(name = "--name", required = true, aliases = {"-n"}, metaVar = "NAME", usage = "name of project to be created")
|
@Option(name = "--name", required = true, aliases = {"-n"}, metaVar = "NAME", usage = "name of project to be created")
|
||||||
private String projectName;
|
private String projectName;
|
||||||
|
|
||||||
@Option(name = "--owner", aliases = {"-o"}, usage = "owner of project\n"
|
@Option(name = "--owner", aliases = {"-o"}, usage = "owner(s) of project")
|
||||||
+ "(default: Administrators)")
|
private List<AccountGroup.Id> ownerIds;
|
||||||
private AccountGroup.Id ownerId;
|
|
||||||
|
|
||||||
@Option(name = "--description", aliases = {"-d"}, metaVar = "DESC", usage = "description of project")
|
@Option(name = "--description", aliases = {"-d"}, metaVar = "DESC", usage = "description of project")
|
||||||
private String projectDescription = "";
|
private String projectDescription = "";
|
||||||
@ -71,7 +75,15 @@ final class AdminCreateProject extends BaseCommand {
|
|||||||
private GitRepositoryManager repoManager;
|
private GitRepositoryManager repoManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private AuthConfig authConfig;
|
@ProjectCreatorGroups
|
||||||
|
private Set<AccountGroup.Id> projectCreatorGroups;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@ProjectOwnerGroups
|
||||||
|
private Set<AccountGroup.Id> projectOwnerGroups;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private IdentifiedUser currentUser;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ReplicationQueue rq;
|
private ReplicationQueue rq;
|
||||||
@ -83,7 +95,6 @@ final class AdminCreateProject extends BaseCommand {
|
|||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
PrintWriter p = toPrintWriter(out);
|
PrintWriter p = toPrintWriter(out);
|
||||||
|
|
||||||
ownerId = authConfig.getAdministratorsGroup();
|
|
||||||
parseCommandLine();
|
parseCommandLine();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -111,16 +122,40 @@ final class AdminCreateProject extends BaseCommand {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any of the elements in the first collection can be found in the
|
||||||
|
* second collection.
|
||||||
|
*
|
||||||
|
* @param findAnyOfThese which elements to look for.
|
||||||
|
* @param inThisCollection where to look for them.
|
||||||
|
* @param <E> type of the elements in question.
|
||||||
|
* @return {@code true} if any of the elements in {@code findAnyOfThese} can
|
||||||
|
* be found in {@code inThisCollection}, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
private static <E> boolean isAnyIncludedIn(Collection<E> findAnyOfThese,
|
||||||
|
Collection<E> inThisCollection) {
|
||||||
|
for (E findThisItem : findAnyOfThese) {
|
||||||
|
if (inThisCollection.contains(findThisItem)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void createProject() throws OrmException {
|
private void createProject() throws OrmException {
|
||||||
final Project.NameKey newProjectNameKey = new Project.NameKey(projectName);
|
final Project.NameKey newProjectNameKey = new Project.NameKey(projectName);
|
||||||
|
|
||||||
final RefRight.Key prk =
|
List<RefRight> access = new ArrayList<RefRight>();
|
||||||
new RefRight.Key(newProjectNameKey, new RefRight.RefPattern(
|
for (AccountGroup.Id ownerId : ownerIds) {
|
||||||
RefRight.ALL), ApprovalCategory.OWN, ownerId);
|
final RefRight.Key prk =
|
||||||
final RefRight pr = new RefRight(prk);
|
new RefRight.Key(newProjectNameKey, new RefRight.RefPattern(
|
||||||
pr.setMaxValue((short) 1);
|
RefRight.ALL), ApprovalCategory.OWN, ownerId);
|
||||||
pr.setMinValue((short) 1);
|
final RefRight pr = new RefRight(prk);
|
||||||
db.refRights().insert(Collections.singleton(pr));
|
pr.setMaxValue((short) 1);
|
||||||
|
pr.setMinValue((short) 1);
|
||||||
|
access.add(pr);
|
||||||
|
}
|
||||||
|
db.refRights().insert(access);
|
||||||
|
|
||||||
final Project newProject = new Project(newProjectNameKey);
|
final Project newProject = new Project(newProjectNameKey);
|
||||||
newProject.setDescription(projectDescription);
|
newProject.setDescription(projectDescription);
|
||||||
@ -137,6 +172,17 @@ final class AdminCreateProject extends BaseCommand {
|
|||||||
projectName.substring(0, projectName.length() - ".git".length());
|
projectName.substring(0, projectName.length() - ".git".length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isAnyIncludedIn(currentUser.getEffectiveGroups(), projectCreatorGroups)) {
|
||||||
|
throw new Failure(1, "fatal: Not permitted to create " + projectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ownerIds != null && !ownerIds.isEmpty()) {
|
||||||
|
ownerIds =
|
||||||
|
new ArrayList<AccountGroup.Id>(new HashSet<AccountGroup.Id>(ownerIds));
|
||||||
|
} else {
|
||||||
|
ownerIds = new ArrayList<AccountGroup.Id>(projectOwnerGroups);
|
||||||
|
}
|
||||||
|
|
||||||
while (branch.startsWith("/")) {
|
while (branch.startsWith("/")) {
|
||||||
branch = branch.substring(1);
|
branch = branch.substring(1);
|
||||||
}
|
}
|
@ -27,7 +27,7 @@ public class MasterCommandModule extends CommandModule {
|
|||||||
|
|
||||||
command(gerrit, "approve").to(ApproveCommand.class);
|
command(gerrit, "approve").to(ApproveCommand.class);
|
||||||
command(gerrit, "create-account").to(AdminCreateAccount.class);
|
command(gerrit, "create-account").to(AdminCreateAccount.class);
|
||||||
command(gerrit, "create-project").to(AdminCreateProject.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);
|
||||||
command(gerrit, "replicate").to(AdminReplicate.class);
|
command(gerrit, "replicate").to(AdminReplicate.class);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user