Support to list child projects recursively via REST
Change-Id: I046e4d546ca1f0a971382816de4ea76aef035f3f Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:

committed by
Gerrit Code Review

parent
5b6c406e38
commit
f95bd17c34
@@ -535,6 +535,63 @@ returned that describe the child projects.
|
|||||||
]
|
]
|
||||||
----
|
----
|
||||||
|
|
||||||
|
To resolve the child projects of a project recursively the parameter
|
||||||
|
`recursive` can be set.
|
||||||
|
|
||||||
|
Child projects that are not visible to the calling user are ignored and
|
||||||
|
are not resolved further.
|
||||||
|
|
||||||
|
.Request
|
||||||
|
----
|
||||||
|
GET /projects/Public-Projects/children/?recursive HTTP/1.0
|
||||||
|
----
|
||||||
|
|
||||||
|
.Response
|
||||||
|
----
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Disposition: attachment
|
||||||
|
Content-Type: application/json;charset=UTF-8
|
||||||
|
|
||||||
|
)]}'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"kind": "gerritcodereview#project",
|
||||||
|
"id": "gerrit",
|
||||||
|
"name": "gerrit",
|
||||||
|
"parent": "Public-Projects",
|
||||||
|
"description": "Gerrit Code Review"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "gerritcodereview#project",
|
||||||
|
"id": "plugins%2Freplication",
|
||||||
|
"name": "plugins/replication",
|
||||||
|
"parent": "Public-Plugins",
|
||||||
|
"description": "Copies to other servers using the Git protocol"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "gerritcodereview#project",
|
||||||
|
"id": "plugins%2Freviewnotes",
|
||||||
|
"name": "plugins/reviewnotes",
|
||||||
|
"parent": "Public-Plugins",
|
||||||
|
"description": "Annotates merged commits using notes on refs/notes/review."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "gerritcodereview#project",
|
||||||
|
"id": "plugins%2Fsingleusergroup",
|
||||||
|
"name": "plugins/singleusergroup",
|
||||||
|
"parent": "Public-Plugins",
|
||||||
|
"description": "GroupBackend enabling users to be directly added to access rules"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "gerritcodereview#project",
|
||||||
|
"id": "Public-Plugins",
|
||||||
|
"name": "Public-Plugins",
|
||||||
|
"parent": "Public-Projects",
|
||||||
|
"description": "Parent project for plugins/*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
----
|
||||||
|
|
||||||
[[get-child-project]]
|
[[get-child-project]]
|
||||||
Get Child Project
|
Get Child Project
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
@@ -93,6 +93,29 @@ public class ListChildProjectsIT extends AbstractDaemonTest {
|
|||||||
assertProjects(Arrays.asList(child1, child2), children);
|
assertProjects(Arrays.asList(child1, child2), children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listChildrenRecursively() throws IOException, JSchException {
|
||||||
|
SshSession sshSession = new SshSession(admin);
|
||||||
|
Project.NameKey child1 = new Project.NameKey("p1");
|
||||||
|
createProject(sshSession, child1.get());
|
||||||
|
createProject(sshSession, "p2");
|
||||||
|
Project.NameKey child1_1 = new Project.NameKey("p1.1");
|
||||||
|
createProject(sshSession, child1_1.get(), child1);
|
||||||
|
Project.NameKey child1_2 = new Project.NameKey("p1.2");
|
||||||
|
createProject(sshSession, child1_2.get(), child1);
|
||||||
|
Project.NameKey child1_1_1 = new Project.NameKey("p1.1.1");
|
||||||
|
createProject(sshSession, child1_1_1.get(), child1_1);
|
||||||
|
Project.NameKey child1_1_1_1 = new Project.NameKey("p1.1.1.1");
|
||||||
|
createProject(sshSession, child1_1_1_1.get(), child1_1_1);
|
||||||
|
|
||||||
|
RestResponse r = GET("/projects/" + child1.get() + "/children/?recursive");
|
||||||
|
assertEquals(HttpStatus.SC_OK, r.getStatusCode());
|
||||||
|
List<ProjectInfo> children =
|
||||||
|
(new Gson()).fromJson(r.getReader(),
|
||||||
|
new TypeToken<List<ProjectInfo>>() {}.getType());
|
||||||
|
assertProjects(Arrays.asList(child1_1, child1_2, child1_1_1, child1_1_1_1), children);
|
||||||
|
}
|
||||||
|
|
||||||
private RestResponse GET(String endpoint) throws IOException {
|
private RestResponse GET(String endpoint) throws IOException {
|
||||||
return session.get(endpoint);
|
return session.get(endpoint);
|
||||||
}
|
}
|
||||||
|
@@ -15,30 +15,49 @@
|
|||||||
package com.google.gerrit.server.project;
|
package com.google.gerrit.server.project;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.config.AllProjectsName;
|
import com.google.gerrit.server.config.AllProjectsName;
|
||||||
import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
|
import com.google.gerrit.server.project.ProjectJson.ProjectInfo;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import org.kohsuke.args4j.Option;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class ListChildProjects implements RestReadView<ProjectResource> {
|
public class ListChildProjects implements RestReadView<ProjectResource> {
|
||||||
|
|
||||||
|
@Option(name = "--recursive", usage = "to list child projects recursively")
|
||||||
|
private boolean recursive;
|
||||||
|
|
||||||
private final ProjectCache projectCache;
|
private final ProjectCache projectCache;
|
||||||
private final AllProjectsName allProjects;
|
private final AllProjectsName allProjects;
|
||||||
private final ProjectJson json;
|
private final ProjectJson json;
|
||||||
|
private final ProjectNode.Factory projectNodeFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ListChildProjects(ProjectCache projectCache, AllProjectsName allProjects,
|
ListChildProjects(ProjectCache projectCache, AllProjectsName allProjects,
|
||||||
ProjectJson json) {
|
ProjectJson json, ProjectNode.Factory projectNodeFactory) {
|
||||||
this.projectCache = projectCache;
|
this.projectCache = projectCache;
|
||||||
this.allProjects = allProjects;
|
this.allProjects = allProjects;
|
||||||
this.json = json;
|
this.json = json;
|
||||||
|
this.projectNodeFactory = projectNodeFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProjectInfo> apply(ProjectResource rsrc) {
|
public List<ProjectInfo> apply(ProjectResource rsrc) {
|
||||||
|
if (recursive) {
|
||||||
|
return getChildProjectsRecursively(rsrc.getNameKey(),
|
||||||
|
rsrc.getControl().getCurrentUser());
|
||||||
|
} else {
|
||||||
|
return getDirectChildProjects(rsrc.getNameKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ProjectInfo> getDirectChildProjects(Project.NameKey parent) {
|
||||||
List<ProjectInfo> childProjects = Lists.newArrayList();
|
List<ProjectInfo> childProjects = Lists.newArrayList();
|
||||||
for (Project.NameKey projectName : projectCache.all()) {
|
for (Project.NameKey projectName : projectCache.all()) {
|
||||||
ProjectState e = projectCache.get(projectName);
|
ProjectState e = projectCache.get(projectName);
|
||||||
@@ -46,10 +65,42 @@ public class ListChildProjects implements RestReadView<ProjectResource> {
|
|||||||
// If we can't get it from the cache, pretend it's not present.
|
// If we can't get it from the cache, pretend it's not present.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rsrc.getNameKey().equals(e.getProject().getParent(allProjects))) {
|
if (parent.equals(e.getProject().getParent(allProjects))) {
|
||||||
childProjects.add(json.format(e.getProject()));
|
childProjects.add(json.format(e.getProject()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return childProjects;
|
return childProjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ProjectInfo> getChildProjectsRecursively(Project.NameKey parent,
|
||||||
|
CurrentUser user) {
|
||||||
|
Map<Project.NameKey, ProjectNode> projects = Maps.newHashMap();
|
||||||
|
for (Project.NameKey name : projectCache.all()) {
|
||||||
|
ProjectState p = projectCache.get(name);
|
||||||
|
if (p == null) {
|
||||||
|
// If we can't get it from the cache, pretend it's not present.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
projects.put(name, projectNodeFactory.create(p.getProject(),
|
||||||
|
p.controlFor(user).isVisible()));
|
||||||
|
}
|
||||||
|
for (ProjectNode key : projects.values()) {
|
||||||
|
ProjectNode node = projects.get(key.getParentName());
|
||||||
|
if (node != null) {
|
||||||
|
node.addChild(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getChildProjectsRecursively(projects.get(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ProjectInfo> getChildProjectsRecursively(ProjectNode p) {
|
||||||
|
List<ProjectInfo> allChildren = Lists.newArrayList();
|
||||||
|
for (ProjectNode c : p.getChildren()) {
|
||||||
|
if (c.isVisible()) {
|
||||||
|
allChildren.add(json.format(c.getProject()));
|
||||||
|
allChildren.addAll(getChildProjectsRecursively(c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allChildren;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -57,6 +57,10 @@ public class ProjectNode implements TreeNode, Comparable<ProjectNode> {
|
|||||||
return allProjectsName.equals(project.getNameKey());
|
return allProjectsName.equals(project.getNameKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Project getProject() {
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return project.getName();
|
return project.getName();
|
||||||
@@ -68,7 +72,7 @@ public class ProjectNode implements TreeNode, Comparable<ProjectNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SortedSet<? extends TreeNode> getChildren() {
|
public SortedSet<? extends ProjectNode> getChildren() {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user