Merge changes I2da2eabd,Iefa35b7e
* changes: SSH: set-project-parent is no longer admin exclusive New option: receive.allowProjectOwnersToChangeParent
This commit is contained in:
commit
a7a33cb437
@ -85,6 +85,9 @@ link:cmd-set-head.html[gerrit set-head]::
|
|||||||
link:cmd-set-project.html[gerrit set-project]::
|
link:cmd-set-project.html[gerrit set-project]::
|
||||||
Change a project's settings.
|
Change a project's settings.
|
||||||
|
|
||||||
|
link:cmd-set-project-parent.html[gerrit set-project-parent]::
|
||||||
|
Change the project permissions are inherited from.
|
||||||
|
|
||||||
link:cmd-set-reviewers.html[gerrit set-reviewers]::
|
link:cmd-set-reviewers.html[gerrit set-reviewers]::
|
||||||
Add or remove reviewers on a change.
|
Add or remove reviewers on a change.
|
||||||
|
|
||||||
@ -178,9 +181,6 @@ link:cmd-set-account.html[gerrit set-account]::
|
|||||||
link:cmd-set-members.html[gerrit set-members]::
|
link:cmd-set-members.html[gerrit set-members]::
|
||||||
Set group members.
|
Set group members.
|
||||||
|
|
||||||
link:cmd-set-project-parent.html[gerrit set-project-parent]::
|
|
||||||
Change the project permissions are inherited from.
|
|
||||||
|
|
||||||
link:cmd-show-caches.html[gerrit show-caches]::
|
link:cmd-show-caches.html[gerrit show-caches]::
|
||||||
Display current cache statistics.
|
Display current cache statistics.
|
||||||
|
|
||||||
|
@ -20,7 +20,11 @@ default this is `All-Projects`. This command sets
|
|||||||
the project to inherit through another one.
|
the project to inherit through another one.
|
||||||
|
|
||||||
== ACCESS
|
== ACCESS
|
||||||
Caller must be a member of the privileged 'Administrators' group.
|
Caller must be a member of the privileged 'Administrators' group
|
||||||
|
or, if
|
||||||
|
link:config-gerrit.html#receive.allowProjectOwnersToChangeParent[receive.allowProjectOwnersToChangeParent]
|
||||||
|
is enabled, be a project owner of the projects that is getting their
|
||||||
|
parent updated.
|
||||||
|
|
||||||
== SCRIPTING
|
== SCRIPTING
|
||||||
This command is intended to be used in scripts.
|
This command is intended to be used in scripts.
|
||||||
|
@ -3670,6 +3670,17 @@ Setting to false to skip the check can decrease latency during push.
|
|||||||
+
|
+
|
||||||
Default is true.
|
Default is true.
|
||||||
|
|
||||||
|
[[receive.allowProjectOwnersToChangeParent]]receive.allowProjectOwnersToChangeParent::
|
||||||
|
+
|
||||||
|
If true, Gerrit will allow project owners to change the parent of a project.
|
||||||
|
+
|
||||||
|
By default only Gerrit administrators are allowed to change the parent
|
||||||
|
of a project. By allowing project owners to change parents, it may
|
||||||
|
allow the owner to circumvent certain enforced rules (like important
|
||||||
|
BLOCK rules).
|
||||||
|
+
|
||||||
|
Default is false.
|
||||||
|
|
||||||
[[receive.checkReferencedObjectsAreReachable]]receive.checkReferencedObjectsAreReachable::
|
[[receive.checkReferencedObjectsAreReachable]]receive.checkReferencedObjectsAreReachable::
|
||||||
+
|
+
|
||||||
If set to true, Gerrit will validate that all referenced objects that
|
If set to true, Gerrit will validate that all referenced objects that
|
||||||
|
@ -361,6 +361,7 @@ class ReceiveCommits {
|
|||||||
private final ReceivePack receivePack;
|
private final ReceivePack receivePack;
|
||||||
|
|
||||||
// Immutable fields derived from constructor arguments.
|
// Immutable fields derived from constructor arguments.
|
||||||
|
private final boolean allowProjectOwnersToChangeParent;
|
||||||
private final boolean allowPushToRefsChanges;
|
private final boolean allowPushToRefsChanges;
|
||||||
private final LabelTypes labelTypes;
|
private final LabelTypes labelTypes;
|
||||||
private final NoteMap rejectCommits;
|
private final NoteMap rejectCommits;
|
||||||
@ -505,6 +506,9 @@ class ReceiveCommits {
|
|||||||
updateGroups = new ArrayList<>();
|
updateGroups = new ArrayList<>();
|
||||||
validCommits = new HashSet<>();
|
validCommits = new HashSet<>();
|
||||||
|
|
||||||
|
this.allowProjectOwnersToChangeParent =
|
||||||
|
cfg.getBoolean("receive", "allowProjectOwnersToChangeParent", false);
|
||||||
|
|
||||||
// Other settings populated during processing.
|
// Other settings populated during processing.
|
||||||
newChangeForAllNotInTarget =
|
newChangeForAllNotInTarget =
|
||||||
projectState.is(BooleanProjectConfig.CREATE_NEW_CHANGE_FOR_ALL_NOT_IN_TARGET);
|
projectState.is(BooleanProjectConfig.CREATE_NEW_CHANGE_FOR_ALL_NOT_IN_TARGET);
|
||||||
@ -1113,11 +1117,24 @@ class ReceiveCommits {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!oldParent.equals(newParent)) {
|
if (!oldParent.equals(newParent)) {
|
||||||
try {
|
if (allowProjectOwnersToChangeParent) {
|
||||||
permissionBackend.user(user).check(GlobalPermission.ADMINISTRATE_SERVER);
|
try {
|
||||||
} catch (AuthException e) {
|
permissionBackend
|
||||||
reject(cmd, "invalid project configuration: only Gerrit admin can set parent");
|
.user(user)
|
||||||
return;
|
.project(project.getNameKey())
|
||||||
|
.check(ProjectPermission.WRITE_CONFIG);
|
||||||
|
} catch (AuthException e) {
|
||||||
|
reject(
|
||||||
|
cmd, "invalid project configuration: only project owners can set parent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
permissionBackend.user(user).check(GlobalPermission.ADMINISTRATE_SERVER);
|
||||||
|
} catch (AuthException e) {
|
||||||
|
reject(cmd, "invalid project configuration: only Gerrit admin can set parent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,12 +32,14 @@ import com.google.gerrit.server.IdentifiedUser;
|
|||||||
import com.google.gerrit.server.account.AccountProperties;
|
import com.google.gerrit.server.account.AccountProperties;
|
||||||
import com.google.gerrit.server.config.AllProjectsName;
|
import com.google.gerrit.server.config.AllProjectsName;
|
||||||
import com.google.gerrit.server.config.AllUsersName;
|
import com.google.gerrit.server.config.AllUsersName;
|
||||||
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.config.PluginConfig;
|
import com.google.gerrit.server.config.PluginConfig;
|
||||||
import com.google.gerrit.server.config.ProjectConfigEntry;
|
import com.google.gerrit.server.config.ProjectConfigEntry;
|
||||||
import com.google.gerrit.server.git.CodeReviewCommit;
|
import com.google.gerrit.server.git.CodeReviewCommit;
|
||||||
import com.google.gerrit.server.permissions.GlobalPermission;
|
import com.google.gerrit.server.permissions.GlobalPermission;
|
||||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||||
|
import com.google.gerrit.server.permissions.ProjectPermission;
|
||||||
import com.google.gerrit.server.project.ProjectCache;
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
import com.google.gerrit.server.project.ProjectConfig;
|
import com.google.gerrit.server.project.ProjectConfig;
|
||||||
import com.google.gerrit.server.project.ProjectState;
|
import com.google.gerrit.server.project.ProjectState;
|
||||||
@ -48,6 +50,7 @@ import com.google.inject.Provider;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
|
import org.eclipse.jgit.lib.Config;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.revwalk.RevWalk;
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
|
|
||||||
@ -114,12 +117,17 @@ public class MergeValidators {
|
|||||||
"Change contains a project configuration that changes the parent"
|
"Change contains a project configuration that changes the parent"
|
||||||
+ " project.\n"
|
+ " project.\n"
|
||||||
+ "The change must be submitted by a Gerrit administrator.";
|
+ "The change must be submitted by a Gerrit administrator.";
|
||||||
|
private static final String SET_BY_OWNER =
|
||||||
|
"Change contains a project configuration that changes the parent"
|
||||||
|
+ " project.\n"
|
||||||
|
+ "The change must be submitted by a Gerrit administrator or the project owner.";
|
||||||
|
|
||||||
private final AllProjectsName allProjectsName;
|
private final AllProjectsName allProjectsName;
|
||||||
private final AllUsersName allUsersName;
|
private final AllUsersName allUsersName;
|
||||||
private final ProjectCache projectCache;
|
private final ProjectCache projectCache;
|
||||||
private final PermissionBackend permissionBackend;
|
private final PermissionBackend permissionBackend;
|
||||||
private final DynamicMap<ProjectConfigEntry> pluginConfigEntries;
|
private final DynamicMap<ProjectConfigEntry> pluginConfigEntries;
|
||||||
|
private final boolean allowProjectOwnersToChangeParent;
|
||||||
|
|
||||||
public interface Factory {
|
public interface Factory {
|
||||||
ProjectConfigValidator create();
|
ProjectConfigValidator create();
|
||||||
@ -131,12 +139,15 @@ public class MergeValidators {
|
|||||||
AllUsersName allUsersName,
|
AllUsersName allUsersName,
|
||||||
ProjectCache projectCache,
|
ProjectCache projectCache,
|
||||||
PermissionBackend permissionBackend,
|
PermissionBackend permissionBackend,
|
||||||
DynamicMap<ProjectConfigEntry> pluginConfigEntries) {
|
DynamicMap<ProjectConfigEntry> pluginConfigEntries,
|
||||||
|
@GerritServerConfig Config config) {
|
||||||
this.allProjectsName = allProjectsName;
|
this.allProjectsName = allProjectsName;
|
||||||
this.allUsersName = allUsersName;
|
this.allUsersName = allUsersName;
|
||||||
this.projectCache = projectCache;
|
this.projectCache = projectCache;
|
||||||
this.permissionBackend = permissionBackend;
|
this.permissionBackend = permissionBackend;
|
||||||
this.pluginConfigEntries = pluginConfigEntries;
|
this.pluginConfigEntries = pluginConfigEntries;
|
||||||
|
this.allowProjectOwnersToChangeParent =
|
||||||
|
config.getBoolean("receive", "allowProjectOwnersToChangeParent", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -162,13 +173,27 @@ public class MergeValidators {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!oldParent.equals(newParent)) {
|
if (!oldParent.equals(newParent)) {
|
||||||
try {
|
if (!allowProjectOwnersToChangeParent) {
|
||||||
permissionBackend.user(caller).check(GlobalPermission.ADMINISTRATE_SERVER);
|
try {
|
||||||
} catch (AuthException e) {
|
permissionBackend.user(caller).check(GlobalPermission.ADMINISTRATE_SERVER);
|
||||||
throw new MergeValidationException(SET_BY_ADMIN);
|
} catch (AuthException e) {
|
||||||
} catch (PermissionBackendException e) {
|
throw new MergeValidationException(SET_BY_ADMIN);
|
||||||
logger.atWarning().withCause(e).log("Cannot check ADMINISTRATE_SERVER");
|
} catch (PermissionBackendException e) {
|
||||||
throw new MergeValidationException("validation unavailable");
|
logger.atWarning().withCause(e).log("Cannot check ADMINISTRATE_SERVER");
|
||||||
|
throw new MergeValidationException("validation unavailable");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
permissionBackend
|
||||||
|
.user(caller)
|
||||||
|
.project(destProject.getNameKey())
|
||||||
|
.check(ProjectPermission.WRITE_CONFIG);
|
||||||
|
} catch (AuthException e) {
|
||||||
|
throw new MergeValidationException(SET_BY_OWNER);
|
||||||
|
} catch (PermissionBackendException e) {
|
||||||
|
logger.atWarning().withCause(e).log("Cannot check WRITE_CONFIG");
|
||||||
|
throw new MergeValidationException("validation unavailable");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (allUsersName.equals(destProject.getNameKey())
|
if (allUsersName.equals(destProject.getNameKey())
|
||||||
&& !allProjectsName.equals(newParent)) {
|
&& !allProjectsName.equals(newParent)) {
|
||||||
|
@ -30,10 +30,12 @@ import com.google.gerrit.reviewdb.client.Project;
|
|||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.config.AllProjectsName;
|
import com.google.gerrit.server.config.AllProjectsName;
|
||||||
import com.google.gerrit.server.config.AllUsersName;
|
import com.google.gerrit.server.config.AllUsersName;
|
||||||
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.git.meta.MetaDataUpdate;
|
import com.google.gerrit.server.git.meta.MetaDataUpdate;
|
||||||
import com.google.gerrit.server.permissions.GlobalPermission;
|
import com.google.gerrit.server.permissions.GlobalPermission;
|
||||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||||
|
import com.google.gerrit.server.permissions.ProjectPermission;
|
||||||
import com.google.gerrit.server.project.ProjectCache;
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
import com.google.gerrit.server.project.ProjectConfig;
|
import com.google.gerrit.server.project.ProjectConfig;
|
||||||
import com.google.gerrit.server.project.ProjectResource;
|
import com.google.gerrit.server.project.ProjectResource;
|
||||||
@ -43,6 +45,7 @@ import com.google.inject.Singleton;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
||||||
|
import org.eclipse.jgit.lib.Config;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class SetParent implements RestModifyView<ProjectResource, ParentInput> {
|
public class SetParent implements RestModifyView<ProjectResource, ParentInput> {
|
||||||
@ -51,6 +54,7 @@ public class SetParent implements RestModifyView<ProjectResource, ParentInput> {
|
|||||||
private final MetaDataUpdate.Server updateFactory;
|
private final MetaDataUpdate.Server updateFactory;
|
||||||
private final AllProjectsName allProjects;
|
private final AllProjectsName allProjects;
|
||||||
private final AllUsersName allUsers;
|
private final AllUsersName allUsers;
|
||||||
|
private final boolean allowProjectOwnersToChangeParent;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SetParent(
|
SetParent(
|
||||||
@ -58,12 +62,15 @@ public class SetParent implements RestModifyView<ProjectResource, ParentInput> {
|
|||||||
PermissionBackend permissionBackend,
|
PermissionBackend permissionBackend,
|
||||||
MetaDataUpdate.Server updateFactory,
|
MetaDataUpdate.Server updateFactory,
|
||||||
AllProjectsName allProjects,
|
AllProjectsName allProjects,
|
||||||
AllUsersName allUsers) {
|
AllUsersName allUsers,
|
||||||
|
@GerritServerConfig Config config) {
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
this.permissionBackend = permissionBackend;
|
this.permissionBackend = permissionBackend;
|
||||||
this.updateFactory = updateFactory;
|
this.updateFactory = updateFactory;
|
||||||
this.allProjects = allProjects;
|
this.allProjects = allProjects;
|
||||||
this.allUsers = allUsers;
|
this.allUsers = allUsers;
|
||||||
|
this.allowProjectOwnersToChangeParent =
|
||||||
|
config.getBoolean("receive", "allowProjectOwnersToChangeParent", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -114,7 +121,11 @@ public class SetParent implements RestModifyView<ProjectResource, ParentInput> {
|
|||||||
throws AuthException, ResourceConflictException, UnprocessableEntityException,
|
throws AuthException, ResourceConflictException, UnprocessableEntityException,
|
||||||
PermissionBackendException, BadRequestException {
|
PermissionBackendException, BadRequestException {
|
||||||
if (checkIfAdmin) {
|
if (checkIfAdmin) {
|
||||||
permissionBackend.user(user).check(GlobalPermission.ADMINISTRATE_SERVER);
|
if (allowProjectOwnersToChangeParent) {
|
||||||
|
permissionBackend.user(user).project(project).check(ProjectPermission.WRITE_CONFIG);
|
||||||
|
} else {
|
||||||
|
permissionBackend.user(user).check(GlobalPermission.ADMINISTRATE_SERVER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project.equals(allUsers) && !allProjects.get().equals(newParent)) {
|
if (project.equals(allUsers) && !allProjects.get().equals(newParent)) {
|
||||||
|
@ -114,7 +114,7 @@ public class DefaultCommandModule extends CommandModule {
|
|||||||
command(gerrit, SetMembersCommand.class);
|
command(gerrit, SetMembersCommand.class);
|
||||||
command(gerrit, CreateBranchCommand.class);
|
command(gerrit, CreateBranchCommand.class);
|
||||||
command(gerrit, SetAccountCommand.class);
|
command(gerrit, SetAccountCommand.class);
|
||||||
command(gerrit, AdminSetParent.class);
|
command(gerrit, SetParentCommand.class);
|
||||||
|
|
||||||
command(testSubmit, TestSubmitRuleCommand.class);
|
command(testSubmit, TestSubmitRuleCommand.class);
|
||||||
command(testSubmit, TestSubmitTypeCommand.class);
|
command(testSubmit, TestSubmitTypeCommand.class);
|
||||||
|
@ -16,41 +16,36 @@ package com.google.gerrit.sshd.commands;
|
|||||||
|
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.gerrit.extensions.api.projects.ParentInput;
|
||||||
import com.google.gerrit.common.data.GlobalCapability;
|
|
||||||
import com.google.gerrit.extensions.annotations.RequiresCapability;
|
|
||||||
import com.google.gerrit.extensions.common.ProjectInfo;
|
import com.google.gerrit.extensions.common.ProjectInfo;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
|
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||||
|
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
|
||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
|
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.server.config.AllProjectsName;
|
|
||||||
import com.google.gerrit.server.git.meta.MetaDataUpdate;
|
|
||||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||||
import com.google.gerrit.server.project.ProjectCache;
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
import com.google.gerrit.server.project.ProjectConfig;
|
|
||||||
import com.google.gerrit.server.project.ProjectResource;
|
import com.google.gerrit.server.project.ProjectResource;
|
||||||
import com.google.gerrit.server.project.ProjectState;
|
import com.google.gerrit.server.project.ProjectState;
|
||||||
import com.google.gerrit.server.restapi.project.ListChildProjects;
|
import com.google.gerrit.server.restapi.project.ListChildProjects;
|
||||||
|
import com.google.gerrit.server.restapi.project.SetParent;
|
||||||
import com.google.gerrit.sshd.CommandMetaData;
|
import com.google.gerrit.sshd.CommandMetaData;
|
||||||
import com.google.gerrit.sshd.SshCommand;
|
import com.google.gerrit.sshd.SshCommand;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
|
||||||
import org.eclipse.jgit.errors.RepositoryNotFoundException;
|
|
||||||
import org.kohsuke.args4j.Argument;
|
import org.kohsuke.args4j.Argument;
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
|
|
||||||
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
|
|
||||||
@CommandMetaData(
|
@CommandMetaData(
|
||||||
name = "set-project-parent",
|
name = "set-project-parent",
|
||||||
description = "Change the project permissions are inherited from")
|
description = "Change the project permissions are inherited from")
|
||||||
final class AdminSetParent extends SshCommand {
|
final class SetParentCommand extends SshCommand {
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
name = "--parent",
|
name = "--parent",
|
||||||
aliases = {"-p"},
|
aliases = {"-p"},
|
||||||
@ -80,14 +75,18 @@ final class AdminSetParent extends SshCommand {
|
|||||||
|
|
||||||
@Inject private ProjectCache projectCache;
|
@Inject private ProjectCache projectCache;
|
||||||
|
|
||||||
@Inject private MetaDataUpdate.User metaDataUpdateFactory;
|
|
||||||
|
|
||||||
@Inject private AllProjectsName allProjectsName;
|
|
||||||
|
|
||||||
@Inject private ListChildProjects listChildProjects;
|
@Inject private ListChildProjects listChildProjects;
|
||||||
|
|
||||||
|
@Inject private SetParent setParent;
|
||||||
|
|
||||||
private Project.NameKey newParentKey;
|
private Project.NameKey newParentKey;
|
||||||
|
|
||||||
|
private static ParentInput parentInput(String parent) {
|
||||||
|
ParentInput input = new ParentInput();
|
||||||
|
input.parent = parent;
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void run() throws Failure {
|
protected void run() throws Failure {
|
||||||
if (oldParent == null && children.isEmpty()) {
|
if (oldParent == null && children.isEmpty()) {
|
||||||
@ -100,25 +99,9 @@ final class AdminSetParent extends SshCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final StringBuilder err = new StringBuilder();
|
final StringBuilder err = new StringBuilder();
|
||||||
final Set<Project.NameKey> grandParents = new HashSet<>();
|
|
||||||
|
|
||||||
grandParents.add(allProjectsName);
|
|
||||||
|
|
||||||
if (newParent != null) {
|
if (newParent != null) {
|
||||||
newParentKey = newParent.getProject().getNameKey();
|
newParentKey = newParent.getProject().getNameKey();
|
||||||
|
|
||||||
// Catalog all grandparents of the "parent", we want to
|
|
||||||
// catch a cycle in the parent pointers before it occurs.
|
|
||||||
//
|
|
||||||
Project.NameKey gp = newParent.getProject().getParent();
|
|
||||||
while (gp != null && grandParents.add(gp)) {
|
|
||||||
final ProjectState s = projectCache.get(gp);
|
|
||||||
if (s != null) {
|
|
||||||
gp = s.getProject().getParent();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Project.NameKey> childProjects =
|
final List<Project.NameKey> childProjects =
|
||||||
@ -135,47 +118,19 @@ final class AdminSetParent extends SshCommand {
|
|||||||
|
|
||||||
for (Project.NameKey nameKey : childProjects) {
|
for (Project.NameKey nameKey : childProjects) {
|
||||||
final String name = nameKey.get();
|
final String name = nameKey.get();
|
||||||
|
ProjectState project = projectCache.get(nameKey);
|
||||||
if (allProjectsName.equals(nameKey)) {
|
|
||||||
// Don't allow the wild card project to have a parent.
|
|
||||||
//
|
|
||||||
err.append("error: Cannot set parent of '").append(name).append("'\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grandParents.contains(nameKey) || nameKey.equals(newParentKey)) {
|
|
||||||
// Try to avoid creating a cycle in the parent pointers.
|
|
||||||
//
|
|
||||||
err.append("error: Cycle exists between '")
|
|
||||||
.append(name)
|
|
||||||
.append("' and '")
|
|
||||||
.append(newParentKey != null ? newParentKey.get() : allProjectsName.get())
|
|
||||||
.append("'\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try (MetaDataUpdate md = metaDataUpdateFactory.create(nameKey)) {
|
|
||||||
ProjectConfig config = ProjectConfig.read(md);
|
|
||||||
config.getProject().setParentName(newParentKey);
|
|
||||||
md.setMessage(
|
|
||||||
"Inherit access from "
|
|
||||||
+ (newParentKey != null ? newParentKey.get() : allProjectsName.get())
|
|
||||||
+ "\n");
|
|
||||||
config.commit(md);
|
|
||||||
} catch (RepositoryNotFoundException notFound) {
|
|
||||||
err.append("error: Project ").append(name).append(" not found\n");
|
|
||||||
} catch (IOException | ConfigInvalidException e) {
|
|
||||||
final String msg = "Cannot update project " + name;
|
|
||||||
logger.atSevere().withCause(e).log(msg);
|
|
||||||
err.append("error: ").append(msg).append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
projectCache.evict(nameKey);
|
setParent.apply(new ProjectResource(project, user), parentInput(newParentKey.get()));
|
||||||
} catch (IOException e) {
|
} catch (AuthException e) {
|
||||||
final String msg = "Cannot reindex project: " + name;
|
err.append("error: insuffient access rights to change parent of '")
|
||||||
logger.atSevere().withCause(e).log(msg);
|
.append(name)
|
||||||
err.append("error: ").append(msg).append("\n");
|
.append("'\n");
|
||||||
|
} catch (ResourceConflictException | ResourceNotFoundException | BadRequestException e) {
|
||||||
|
err.append("error: ").append(e.getMessage()).append("'\n");
|
||||||
|
} catch (UnprocessableEntityException | IOException e) {
|
||||||
|
throw new Failure(1, "failure in request", e);
|
||||||
|
} catch (PermissionBackendException e) {
|
||||||
|
throw new Failure(1, "permissions unavailable", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -17,13 +17,16 @@ package com.google.gerrit.acceptance.api.project;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||||
|
import com.google.gerrit.acceptance.GerritConfig;
|
||||||
import com.google.gerrit.acceptance.NoHttpd;
|
import com.google.gerrit.acceptance.NoHttpd;
|
||||||
|
import com.google.gerrit.common.data.Permission;
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||||
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
import com.google.gerrit.server.config.AllProjectsNameProvider;
|
||||||
|
import com.google.gerrit.server.group.SystemGroupBackend;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@NoHttpd
|
@NoHttpd
|
||||||
@ -37,6 +40,40 @@ public class SetParentIT extends AbstractDaemonTest {
|
|||||||
gApi.projects().name(project.get()).parent(parent);
|
gApi.projects().name(project.get()).parent(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "receive.allowProjectOwnersToChangeParent", value = "true")
|
||||||
|
public void setParentNotAllowedForNonOwners() throws Exception {
|
||||||
|
String parent = createProject("parent", null, true).get();
|
||||||
|
setApiUser(user);
|
||||||
|
exception.expect(AuthException.class);
|
||||||
|
gApi.projects().name(project.get()).parent(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "receive.allowProjectOwnersToChangeParent", value = "true")
|
||||||
|
public void setParentAllowedByAdminWhenAllowProjectOwnersEnabled() throws Exception {
|
||||||
|
String parent = createProject("parent", null, true).get();
|
||||||
|
|
||||||
|
gApi.projects().name(project.get()).parent(parent);
|
||||||
|
assertThat(gApi.projects().name(project.get()).parent()).isEqualTo(parent);
|
||||||
|
|
||||||
|
// When the parent name is not explicitly set, it should be
|
||||||
|
// set to "All-Projects".
|
||||||
|
gApi.projects().name(project.get()).parent(null);
|
||||||
|
assertThat(gApi.projects().name(project.get()).parent())
|
||||||
|
.isEqualTo(AllProjectsNameProvider.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@GerritConfig(name = "receive.allowProjectOwnersToChangeParent", value = "true")
|
||||||
|
public void setParentAllowedForOwners() throws Exception {
|
||||||
|
String parent = createProject("parent", null, true).get();
|
||||||
|
setApiUser(user);
|
||||||
|
grant(project, "refs/*", Permission.OWNER, false, SystemGroupBackend.REGISTERED_USERS);
|
||||||
|
gApi.projects().name(project.get()).parent(parent);
|
||||||
|
assertThat(gApi.projects().name(project.get()).parent()).isEqualTo(parent);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setParent() throws Exception {
|
public void setParent() throws Exception {
|
||||||
String parent = createProject("parent", null, true).get();
|
String parent = createProject("parent", null, true).get();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user