ListProjects: Allow to filter list by project state

Bug: Issue 7747
Change-Id: Ibf39b408fce8e76a61706ae45da433faaf0391f2
This commit is contained in:
David Pursehouse
2017-11-28 13:37:48 +09:00
parent 1b1bb97571
commit 54508764eb
5 changed files with 88 additions and 13 deletions

View File

@@ -325,7 +325,8 @@ GET /projects/?type=PERMISSIONS HTTP/1.0
---- ----
All:: All::
Get all projects, including those whose state is "HIDDEN". Get all projects, including those whose state is "HIDDEN". May not be used
together with the `state` option.
+ +
.Request .Request
---- ----
@@ -351,6 +352,30 @@ GET /projects/?all HTTP/1.0
} }
---- ----
State(s)::
Get all projects with the given state. May not be used together with the
`all` option.
+
.Request
----
GET /projects/?state=HIDDEN HTTP/1.0
----
+
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: application/json; charset=UTF-8
)]}'
{
"some-other-project": {
"id": "some-other-project",
"state": "HIDDEN"
}
}
----
[[query-projects]] [[query-projects]]
=== Query Projects === Query Projects
-- --

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.extensions.api.projects; package com.google.gerrit.extensions.api.projects;
import com.google.gerrit.extensions.client.ProjectState;
import com.google.gerrit.extensions.common.ProjectInfo; import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.NotImplementedException; import com.google.gerrit.extensions.restapi.NotImplementedException;
import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestApiException;
@@ -94,6 +95,7 @@ public interface Projects {
private boolean showTree; private boolean showTree;
private boolean all; private boolean all;
private FilterType type = FilterType.ALL; private FilterType type = FilterType.ALL;
private ProjectState state = null;
public List<ProjectInfo> get() throws RestApiException { public List<ProjectInfo> get() throws RestApiException {
Map<String, ProjectInfo> map = getAsMap(); Map<String, ProjectInfo> map = getAsMap();
@@ -158,6 +160,11 @@ public interface Projects {
return this; return this;
} }
public ListRequest withState(ProjectState state) {
this.state = state;
return this;
}
public boolean getDescription() { public boolean getDescription() {
return description; return description;
} }
@@ -197,6 +204,10 @@ public interface Projects {
public boolean isAll() { public boolean isAll() {
return all; return all;
} }
public ProjectState getState() {
return state;
}
} }
/** /**

View File

@@ -131,6 +131,8 @@ class ProjectsImpl implements Projects {
lp.setAll(request.isAll()); lp.setAll(request.isAll());
lp.setState(request.getState());
return lp.apply(); return lp.apply();
} }

View File

@@ -190,6 +190,15 @@ public class ListProjects implements RestReadView<TopLevelResource> {
this.all = all; this.all = all;
} }
@Option(
name = "--state",
aliases = {"-s"},
usage = "filter by project state"
)
public void setState(com.google.gerrit.extensions.client.ProjectState state) {
this.state = state;
}
@Option( @Option(
name = "--limit", name = "--limit",
aliases = {"-n"}, aliases = {"-n"},
@@ -249,6 +258,7 @@ public class ListProjects implements RestReadView<TopLevelResource> {
private FilterType type = FilterType.ALL; private FilterType type = FilterType.ALL;
private boolean showDescription; private boolean showDescription;
private boolean all; private boolean all;
private com.google.gerrit.extensions.client.ProjectState state;
private int limit; private int limit;
private int start; private int start;
private String matchPrefix; private String matchPrefix;
@@ -318,6 +328,9 @@ public class ListProjects implements RestReadView<TopLevelResource> {
public SortedMap<String, ProjectInfo> display(@Nullable OutputStream displayOutputStream) public SortedMap<String, ProjectInfo> display(@Nullable OutputStream displayOutputStream)
throws BadRequestException, PermissionBackendException { throws BadRequestException, PermissionBackendException {
if (all && state != null) {
throw new BadRequestException("'all' and 'state' may not be used together");
}
if (groupUuid != null) { if (groupUuid != null) {
try { try {
if (!groupControlFactory.controlFor(groupUuid).isVisible()) { if (!groupControlFactory.controlFor(groupUuid).isVisible()) {
@@ -349,9 +362,14 @@ public class ListProjects implements RestReadView<TopLevelResource> {
try { try {
for (Project.NameKey projectName : filter(perm)) { for (Project.NameKey projectName : filter(perm)) {
final ProjectState e = projectCache.get(projectName); final ProjectState e = projectCache.get(projectName);
if (e == null || (!all && e.getProject().getState() == HIDDEN)) { if (e == null || (e.getProject().getState() == HIDDEN && !all && state != HIDDEN)) {
// If we can't get it from the cache, pretend its not present. // If we can't get it from the cache, pretend it's not present.
// If all wasn't selected, and its HIDDEN, pretend its not present. // If all wasn't selected, and it's HIDDEN, pretend it's not present.
// If state HIDDEN wasn't selected, and it's HIDDEN, pretend it's not present.
continue;
}
if (state != null && e.getProject().getState() != state) {
continue; continue;
} }

View File

@@ -191,37 +191,56 @@ public class ListProjectsIT extends AbstractDaemonTest {
} }
@Test @Test
public void listWithHiddenProject() throws Exception { public void listWithHiddenAndReadonlyProjects() throws Exception {
Project.NameKey hidden = createProject("project-to-hide"); Project.NameKey hidden = createProject("project-to-hide");
Project.NameKey readonly = createProject("project-to-read");
// The project is included because it was not hidden yet // Set project read-only
ConfigInput input = new ConfigInput();
input.state = ProjectState.READ_ONLY;
ConfigInfo info = gApi.projects().name(readonly.get()).config(input);
assertThat(info.state).isEqualTo(input.state);
// The hidden project is included because it was not hidden yet.
// The read-only project is included.
assertThatNameList(gApi.projects().list().get()) assertThatNameList(gApi.projects().list().get())
.containsExactly(allProjects, allUsers, project, hidden) .containsExactly(allProjects, allUsers, project, hidden, readonly)
.inOrder(); .inOrder();
// Hide the project // Hide the project
ConfigInput input = new ConfigInput();
input.state = ProjectState.HIDDEN; input.state = ProjectState.HIDDEN;
ConfigInfo info = gApi.projects().name(hidden.get()).config(input); info = gApi.projects().name(hidden.get()).config(input);
assertThat(info.state).isEqualTo(input.state); assertThat(info.state).isEqualTo(input.state);
// Project is still accessible directly // Project is still accessible directly
gApi.projects().name(hidden.get()).get(); gApi.projects().name(hidden.get()).get();
// But is not included in the list // Hidden project is not included in the list
assertThatNameList(gApi.projects().list().get()) assertThatNameList(gApi.projects().list().get())
.containsExactly(allProjects, allUsers, project) .containsExactly(allProjects, allUsers, project, readonly)
.inOrder(); .inOrder();
// ALL filter applies to type, and doesn't include hidden state // ALL filter applies to type, and doesn't include hidden state
assertThatNameList(gApi.projects().list().withType(FilterType.ALL).get()) assertThatNameList(gApi.projects().list().withType(FilterType.ALL).get())
.containsExactly(allProjects, allUsers, project) .containsExactly(allProjects, allUsers, project, readonly)
.inOrder(); .inOrder();
// "All" boolean option causes hidden projects to be included // "All" boolean option causes hidden projects to be included
assertThatNameList(gApi.projects().list().withAll(true).get()) assertThatNameList(gApi.projects().list().withAll(true).get())
.containsExactly(allProjects, allUsers, project, hidden) .containsExactly(allProjects, allUsers, project, hidden, readonly)
.inOrder(); .inOrder();
// "State" option causes only the projects in that state to be included
assertThatNameList(gApi.projects().list().withState(ProjectState.HIDDEN).get())
.containsExactly(hidden);
assertThatNameList(gApi.projects().list().withState(ProjectState.READ_ONLY).get())
.containsExactly(readonly);
assertThatNameList(gApi.projects().list().withState(ProjectState.ACTIVE).get())
.containsExactly(allProjects, allUsers, project)
.inOrder();
// Cannot use "all" and "state" together
assertBadRequest(gApi.projects().list().withAll(true).withState(ProjectState.ACTIVE));
} }
private void assertBadRequest(ListRequest req) throws Exception { private void assertBadRequest(ListRequest req) throws Exception {