diff --git a/Documentation/cmd-ls-projects.txt b/Documentation/cmd-ls-projects.txt index d7d5aa59d1..26530bd8e1 100644 --- a/Documentation/cmd-ls-projects.txt +++ b/Documentation/cmd-ls-projects.txt @@ -16,6 +16,7 @@ SYNOPSIS [--format {text | json | json_compact}] [--all] [--limit ] + [--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 diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java index e5a11ca82a..47c76ff981 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ListProjects.java @@ -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, diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java index 513f1b1920..b6d53e34d7 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java @@ -120,6 +120,7 @@ public class ProjectControl { private final Collection contributorAgreements; private List allSections; + private List localSections; private Map refControls; private Boolean declaredOwner; @@ -239,8 +240,17 @@ public class ProjectControl { } public Set getAllGroups() { + return getGroups(access()); + } + + public Set getLocalGroups() { + return getGroups(localAccess()); + } + + private static Set getGroups( + final List sectionMatcherList) { final Set all = new HashSet(); - 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 localAccess() { + if (localSections == null) { + localSections = state.getLocalAccessSections(); + } + return localSections; + } + boolean match(PermissionRule rule) { return match(rule.getGroup().getUUID()); } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java index e06c948064..74c1247a5f 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java @@ -174,7 +174,7 @@ public class ProjectState { } /** Get the sections that pertain only to this project. */ - private List getLocalAccessSections() { + List getLocalAccessSections() { List sm = localAccessSections; if (sm == null) { Collection fromConfig = config.getAccessSections();