ls-projects: Add option to list projects on which a certain group is used

Add a --has-acl-for option to the ls-projects command that allows to
list only projects on which access rights for the specified group are
assigned directly. Projects which only inherit access rights for this
group are not listed.

With this option you can find out on which projects a group is (still)
used, e.g. before removing a group (by deletion in the database).

Change-Id: Iab139425808766fbf4e352584b0035fe1c071d93
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin
2012-08-24 15:34:20 +02:00
parent 96a10ed60e
commit f0c7042b17
4 changed files with 58 additions and 5 deletions

View File

@@ -16,6 +16,7 @@ SYNOPSIS
[--format {text | json | json_compact}]
[--all]
[--limit <N>]
[--has-acl-for GROUP]
DESCRIPTION
-----------
@@ -91,6 +92,13 @@ used to unescape the output.
--limit::
Cap the number of results to the first N matches.
--has-acl-for::
Display only projects on which access rights for this group are
directly assigned. Projects which only inherit access rights for
this group are not listed.
+
With this option you can find out on which projects a group is used.
HTTP
----
This command is also available over HTTP, as `/projects/` for

View File

@@ -15,11 +15,16 @@
package com.google.gerrit.server.project;
import com.google.common.collect.Maps;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.Project.NameKey;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.StringUtil;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupControl;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.util.TreeFormatter;
import com.google.gson.reflect.TypeToken;
@@ -86,6 +91,8 @@ public class ListProjects {
private final CurrentUser currentUser;
private final ProjectCache projectCache;
private final GroupCache groupCache;
private final GroupControl.Factory groupControlFactory;
private final GitRepositoryManager repoManager;
private final ProjectNode.Factory projectNodeFactory;
@@ -115,12 +122,18 @@ public class ListProjects {
private String matchPrefix;
@Option(name = "--has-acl-for", metaVar = "GROUP", usage =
"displays only projects on which access rights for this group are directly assigned")
private AccountGroup.Id groupId;
@Inject
protected ListProjects(CurrentUser currentUser, ProjectCache projectCache,
GitRepositoryManager repoManager,
ProjectNode.Factory projectNodeFactory) {
GroupCache groupCache, GroupControl.Factory groupControlFactory,
GitRepositoryManager repoManager, ProjectNode.Factory projectNodeFactory) {
this.currentUser = currentUser;
this.projectCache = projectCache;
this.groupCache = groupCache;
this.groupControlFactory = groupControlFactory;
this.repoManager = repoManager;
this.projectNodeFactory = projectNodeFactory;
}
@@ -175,6 +188,22 @@ public class ListProjects {
//
continue;
}
final ProjectControl pctl = e.controlFor(currentUser);
if (groupId != null) {
try {
if (!groupControlFactory.controlFor(groupId).isVisible()) {
break;
}
} catch (NoSuchGroupException ex) {
break;
}
if (!pctl.getLocalGroups().contains(
GroupReference.forGroup(groupCache.get(groupId)))) {
continue;
}
}
ProjectInfo info = new ProjectInfo();
if (type == FilterType.PARENT_CANDIDATES) {
ProjectState parentState = e.getParentState();
@@ -194,7 +223,6 @@ public class ListProjects {
}
} else {
final ProjectControl pctl = e.controlFor(currentUser);
final boolean isVisible = pctl.isVisible() || (all && pctl.isOwner());
if (showTree && !format.isJson()) {
treeMap.put(projectName,

View File

@@ -120,6 +120,7 @@ public class ProjectControl {
private final Collection<ContributorAgreement> contributorAgreements;
private List<SectionMatcher> allSections;
private List<SectionMatcher> localSections;
private Map<String, RefControl> refControls;
private Boolean declaredOwner;
@@ -239,8 +240,17 @@ public class ProjectControl {
}
public Set<GroupReference> getAllGroups() {
return getGroups(access());
}
public Set<GroupReference> getLocalGroups() {
return getGroups(localAccess());
}
private static Set<GroupReference> getGroups(
final List<SectionMatcher> sectionMatcherList) {
final Set<GroupReference> all = new HashSet<GroupReference>();
for (final SectionMatcher matcher : access()) {
for (final SectionMatcher matcher : sectionMatcherList) {
final AccessSection section = matcher.section;
for (final Permission permission : section.getPermissions()) {
for (final PermissionRule rule : permission.getRules()) {
@@ -392,6 +402,13 @@ public class ProjectControl {
return allSections;
}
private List<SectionMatcher> localAccess() {
if (localSections == null) {
localSections = state.getLocalAccessSections();
}
return localSections;
}
boolean match(PermissionRule rule) {
return match(rule.getGroup().getUUID());
}

View File

@@ -174,7 +174,7 @@ public class ProjectState {
}
/** Get the sections that pertain only to this project. */
private List<SectionMatcher> getLocalAccessSections() {
List<SectionMatcher> getLocalAccessSections() {
List<SectionMatcher> sm = localAccessSections;
if (sm == null) {
Collection<AccessSection> fromConfig = config.getAccessSections();