From 54508764eb5cbb9390d03f41c50a2afb14dded5e Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Tue, 28 Nov 2017 13:37:48 +0900 Subject: [PATCH] ListProjects: Allow to filter list by project state Bug: Issue 7747 Change-Id: Ibf39b408fce8e76a61706ae45da433faaf0391f2 --- Documentation/rest-api-projects.txt | 27 +++++++++++++- .../extensions/api/projects/Projects.java | 11 ++++++ .../server/api/projects/ProjectsImpl.java | 2 + .../gerrit/server/project/ListProjects.java | 24 ++++++++++-- .../rest/project/ListProjectsIT.java | 37 ++++++++++++++----- 5 files changed, 88 insertions(+), 13 deletions(-) diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt index 2cc78a4b60..5984ea1e4c 100644 --- a/Documentation/rest-api-projects.txt +++ b/Documentation/rest-api-projects.txt @@ -325,7 +325,8 @@ GET /projects/?type=PERMISSIONS HTTP/1.0 ---- 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 ---- @@ -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 -- diff --git a/java/com/google/gerrit/extensions/api/projects/Projects.java b/java/com/google/gerrit/extensions/api/projects/Projects.java index cdf99a4a8b..85ec26fd0c 100644 --- a/java/com/google/gerrit/extensions/api/projects/Projects.java +++ b/java/com/google/gerrit/extensions/api/projects/Projects.java @@ -14,6 +14,7 @@ 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.restapi.NotImplementedException; import com.google.gerrit.extensions.restapi.RestApiException; @@ -94,6 +95,7 @@ public interface Projects { private boolean showTree; private boolean all; private FilterType type = FilterType.ALL; + private ProjectState state = null; public List get() throws RestApiException { Map map = getAsMap(); @@ -158,6 +160,11 @@ public interface Projects { return this; } + public ListRequest withState(ProjectState state) { + this.state = state; + return this; + } + public boolean getDescription() { return description; } @@ -197,6 +204,10 @@ public interface Projects { public boolean isAll() { return all; } + + public ProjectState getState() { + return state; + } } /** diff --git a/java/com/google/gerrit/server/api/projects/ProjectsImpl.java b/java/com/google/gerrit/server/api/projects/ProjectsImpl.java index 0438a23427..dee9ebbdae 100644 --- a/java/com/google/gerrit/server/api/projects/ProjectsImpl.java +++ b/java/com/google/gerrit/server/api/projects/ProjectsImpl.java @@ -131,6 +131,8 @@ class ProjectsImpl implements Projects { lp.setAll(request.isAll()); + lp.setState(request.getState()); + return lp.apply(); } diff --git a/java/com/google/gerrit/server/project/ListProjects.java b/java/com/google/gerrit/server/project/ListProjects.java index 177141ec4d..19a5f55ffd 100644 --- a/java/com/google/gerrit/server/project/ListProjects.java +++ b/java/com/google/gerrit/server/project/ListProjects.java @@ -190,6 +190,15 @@ public class ListProjects implements RestReadView { 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( name = "--limit", aliases = {"-n"}, @@ -249,6 +258,7 @@ public class ListProjects implements RestReadView { private FilterType type = FilterType.ALL; private boolean showDescription; private boolean all; + private com.google.gerrit.extensions.client.ProjectState state; private int limit; private int start; private String matchPrefix; @@ -318,6 +328,9 @@ public class ListProjects implements RestReadView { public SortedMap display(@Nullable OutputStream displayOutputStream) throws BadRequestException, PermissionBackendException { + if (all && state != null) { + throw new BadRequestException("'all' and 'state' may not be used together"); + } if (groupUuid != null) { try { if (!groupControlFactory.controlFor(groupUuid).isVisible()) { @@ -349,9 +362,14 @@ public class ListProjects implements RestReadView { try { for (Project.NameKey projectName : filter(perm)) { final ProjectState e = projectCache.get(projectName); - if (e == null || (!all && e.getProject().getState() == HIDDEN)) { - // If we can't get it from the cache, pretend its not present. - // If all wasn't selected, and its HIDDEN, pretend its not present. + if (e == null || (e.getProject().getState() == HIDDEN && !all && state != HIDDEN)) { + // If we can't get it from the cache, pretend it's 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; } diff --git a/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java b/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java index df274e9733..ffde0734d0 100644 --- a/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java +++ b/javatests/com/google/gerrit/acceptance/rest/project/ListProjectsIT.java @@ -191,37 +191,56 @@ public class ListProjectsIT extends AbstractDaemonTest { } @Test - public void listWithHiddenProject() throws Exception { + public void listWithHiddenAndReadonlyProjects() throws Exception { 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()) - .containsExactly(allProjects, allUsers, project, hidden) + .containsExactly(allProjects, allUsers, project, hidden, readonly) .inOrder(); // Hide the project - ConfigInput input = new ConfigInput(); 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); // Project is still accessible directly 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()) - .containsExactly(allProjects, allUsers, project) + .containsExactly(allProjects, allUsers, project, readonly) .inOrder(); // ALL filter applies to type, and doesn't include hidden state assertThatNameList(gApi.projects().list().withType(FilterType.ALL).get()) - .containsExactly(allProjects, allUsers, project) + .containsExactly(allProjects, allUsers, project, readonly) .inOrder(); // "All" boolean option causes hidden projects to be included assertThatNameList(gApi.projects().list().withAll(true).get()) - .containsExactly(allProjects, allUsers, project, hidden) + .containsExactly(allProjects, allUsers, project, hidden, readonly) .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 {