Merge branch 'stable-2.16'

* stable-2.16:
  ListChildProjects: Make settting recursive option chainable
  ListChildProjects: Add limit option
  ListChildProjects: Use parent predicate to find child projects
  QueryProjects: Make setter methods chainable
  Project index: Add parent predicate

ListChildProjectsIT#listChildrenWithLimit is adjusted to use the
ProjectOperations interface.

Change-Id: I185c204f6acbf542f7d80454fe67ce892147473a
This commit is contained in:
David Pursehouse
2019-02-05 10:16:20 +09:00
13 changed files with 133 additions and 56 deletions

View File

@@ -70,7 +70,6 @@ import com.google.gerrit.server.restapi.project.GetHead;
import com.google.gerrit.server.restapi.project.GetParent;
import com.google.gerrit.server.restapi.project.Index;
import com.google.gerrit.server.restapi.project.ListBranches;
import com.google.gerrit.server.restapi.project.ListChildProjects;
import com.google.gerrit.server.restapi.project.ListDashboards;
import com.google.gerrit.server.restapi.project.ListTags;
import com.google.gerrit.server.restapi.project.ProjectsCollection;
@@ -475,10 +474,17 @@ public class ProjectApiImpl implements ProjectApi {
@Override
public List<ProjectInfo> children(boolean recursive) throws RestApiException {
ListChildProjects list = children.list();
list.setRecursive(recursive);
try {
return list.apply(checkExists());
return children.list().withRecursive(recursive).apply(checkExists());
} catch (Exception e) {
throw asRestApiException("Cannot list children", e);
}
}
@Override
public List<ProjectInfo> children(int limit) throws RestApiException {
try {
return children.list().withLimit(limit).apply(checkExists());
} catch (Exception e) {
throw asRestApiException("Cannot list children", e);
}

View File

@@ -150,12 +150,12 @@ class ProjectsImpl implements Projects {
private List<ProjectInfo> query(QueryRequest r) throws RestApiException {
try {
QueryProjects myQueryProjects = queryProvider.get();
myQueryProjects.setQuery(r.getQuery());
myQueryProjects.setLimit(r.getLimit());
myQueryProjects.setStart(r.getStart());
return myQueryProjects.apply(TopLevelResource.INSTANCE);
return queryProvider
.get()
.withQuery(r.getQuery())
.withLimit(r.getLimit())
.withStart(r.getStart())
.apply(TopLevelResource.INSTANCE);
} catch (OrmException e) {
throw new RestApiException("Cannot query projects", e);
}

View File

@@ -27,6 +27,10 @@ public class ProjectPredicates {
return new ProjectPredicate(ProjectField.NAME, nameKey.get());
}
public static Predicate<ProjectData> parent(Project.NameKey parentNameKey) {
return new ProjectPredicate(ProjectField.PARENT_NAME, parentNameKey.get());
}
public static Predicate<ProjectData> inname(String name) {
return new ProjectPredicate(ProjectField.NAME_PART, name.toLowerCase(Locale.US));
}

View File

@@ -44,6 +44,11 @@ public class ProjectQueryBuilder extends QueryBuilder<ProjectData> {
return ProjectPredicates.name(new Project.NameKey(name));
}
@Operator
public Predicate<ProjectData> parent(String parentName) {
return ProjectPredicates.parent(new Project.NameKey(parentName));
}
@Operator
public Predicate<ProjectData> inname(String namePart) {
if (namePart.isEmpty()) {

View File

@@ -22,9 +22,8 @@ import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.api.projects.IndexProjectInput;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.index.project.ProjectIndexer;
import com.google.gerrit.reviewdb.client.Project;
@@ -59,15 +58,12 @@ public class Index implements RestModifyView<ProjectResource, IndexProjectInput>
@Override
public Response.Accepted apply(ProjectResource rsrc, IndexProjectInput input)
throws IOException, AuthException, OrmException, PermissionBackendException,
ResourceConflictException {
throws IOException, OrmException, PermissionBackendException, RestApiException {
String response = "Project " + rsrc.getName() + " submitted for reindexing";
reindex(rsrc.getNameKey(), input.async);
if (Boolean.TRUE.equals(input.indexChildren)) {
ListChildProjects listChildProjects = listChildProjectsProvider.get();
listChildProjects.setRecursive(true);
for (ProjectInfo child : listChildProjects.apply(rsrc)) {
for (ProjectInfo child : listChildProjectsProvider.get().withRecursive(true).apply(rsrc)) {
reindex(new Project.NameKey(child.name), input.async);
}

View File

@@ -17,22 +17,21 @@ package com.google.gerrit.server.restapi.project;
import static java.util.stream.Collectors.toList;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.ProjectPermission;
import com.google.gerrit.server.project.ChildProjects;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectJson;
import com.google.gerrit.server.project.ProjectResource;
import com.google.gerrit.server.project.ProjectState;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import java.util.HashMap;
import com.google.inject.Provider;
import java.util.List;
import java.util.Map;
import org.kohsuke.args4j.Option;
public class ListChildProjects implements RestReadView<ProjectResource> {
@@ -40,33 +39,42 @@ public class ListChildProjects implements RestReadView<ProjectResource> {
@Option(name = "--recursive", usage = "to list child projects recursively")
private boolean recursive;
private final ProjectCache projectCache;
@Option(name = "--limit", usage = "maximum number of parents projects to list")
private int limit;
private final PermissionBackend permissionBackend;
private final AllProjectsName allProjects;
private final ProjectJson json;
private final ChildProjects childProjects;
private final Provider<QueryProjects> queryProvider;
@Inject
ListChildProjects(
ProjectCache projectCache,
PermissionBackend permissionBackend,
AllProjectsName allProjectsName,
ProjectJson json,
ChildProjects childProjects) {
this.projectCache = projectCache;
ChildProjects childProjects,
Provider<QueryProjects> queryProvider) {
this.permissionBackend = permissionBackend;
this.allProjects = allProjectsName;
this.json = json;
this.childProjects = childProjects;
this.queryProvider = queryProvider;
}
public void setRecursive(boolean recursive) {
public ListChildProjects withRecursive(boolean recursive) {
this.recursive = recursive;
return this;
}
public ListChildProjects withLimit(int limit) {
this.limit = limit;
return this;
}
@Override
public List<ProjectInfo> apply(ProjectResource rsrc)
throws PermissionBackendException, ResourceConflictException {
throws PermissionBackendException, OrmException, RestApiException {
if (limit < 0) {
throw new BadRequestException("limit must be a positive number");
}
if (recursive && limit != 0) {
throw new ResourceConflictException("recursive and limit options are mutually exclusive");
}
rsrc.getProjectState().checkStatePermitsRead();
if (recursive) {
return childProjects.list(rsrc.getNameKey());
@@ -76,22 +84,19 @@ public class ListChildProjects implements RestReadView<ProjectResource> {
}
private List<ProjectInfo> directChildProjects(Project.NameKey parent)
throws PermissionBackendException {
Map<Project.NameKey, Project> children = new HashMap<>();
for (Project.NameKey name : projectCache.all()) {
ProjectState c = projectCache.get(name);
if (c != null
&& parent.equals(c.getProject().getParent(allProjects))
&& c.statePermitsRead()) {
children.put(c.getNameKey(), c.getProject());
}
}
return permissionBackend
.currentUser()
.filter(ProjectPermission.ACCESS, children.keySet())
throws OrmException, RestApiException {
PermissionBackend.WithUser currentUser = permissionBackend.currentUser();
return queryProvider
.get()
.withQuery("parent:" + parent.get())
.withLimit(limit)
.apply(TopLevelResource.INSTANCE)
.stream()
.sorted()
.map((p) -> json.format(children.get(p)))
.filter(
p ->
currentUser
.project(new Project.NameKey(p.name))
.testOrFalse(ProjectPermission.ACCESS))
.collect(toList());
}
}

View File

@@ -49,8 +49,9 @@ public class QueryProjects implements RestReadView<TopLevelResource> {
name = "--query",
aliases = {"-q"},
usage = "project query")
public void setQuery(String query) {
public QueryProjects withQuery(String query) {
this.query = query;
return this;
}
@Option(
@@ -58,8 +59,9 @@ public class QueryProjects implements RestReadView<TopLevelResource> {
aliases = {"-n"},
metaVar = "CNT",
usage = "maximum number of projects to list")
public void setLimit(int limit) {
public QueryProjects withLimit(int limit) {
this.limit = limit;
return this;
}
@Option(
@@ -67,8 +69,9 @@ public class QueryProjects implements RestReadView<TopLevelResource> {
aliases = {"-S"},
metaVar = "CNT",
usage = "number of projects to skip")
public void setStart(int start) {
public QueryProjects withStart(int start) {
this.start = start;
return this;
}
@Inject