]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9181 WS api/projects/search search by component keys or uuids
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 5 Sep 2017 15:38:36 +0000 (17:38 +0200)
committerStas Vilchik <stas.vilchik@sonarsource.com>
Mon, 11 Sep 2017 09:28:29 +0000 (11:28 +0200)
13 files changed:
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java
server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentQueryTest.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java
server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsService.java
sonar-ws/src/main/java/org/sonarqube/ws/client/project/ProjectsWsParameters.java
sonar-ws/src/main/java/org/sonarqube/ws/client/project/SearchWsRequest.java
sonar-ws/src/test/java/org/sonarqube/ws/client/project/SearchWsRequestTest.java
tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectSearchTest.java

index 0f1d4fb8de027a6f59e58c2f2e2c1aba39210dfe..e5379b9ab91cd0250c2fcb767baed7eeec5d14d2 100644 (file)
@@ -51,18 +51,17 @@ import static org.sonar.db.WildcardPosition.BEFORE_AND_AFTER;
 public class ComponentDao implements Dao {
 
   private static List<ComponentDto> selectByQueryImpl(DbSession session, @Nullable String organizationUuid, ComponentQuery query, int offset, int limit) {
-    Set<Long> componentIds = query.getComponentIds();
-    if (componentIds != null && componentIds.isEmpty()) {
+    if (query.hasEmptySetOfComponents()) {
       return emptyList();
     }
     return mapper(session).selectByQuery(organizationUuid, query, new RowBounds(offset, limit));
   }
 
   private static int countByQueryImpl(DbSession session, @Nullable String organizationUuid, ComponentQuery query) {
-    Set<Long> componentIds = query.getComponentIds();
-    if (componentIds != null && componentIds.isEmpty()) {
+    if (query.hasEmptySetOfComponents()) {
       return 0;
     }
+
     return mapper(session).countByQuery(organizationUuid, query);
   }
 
index 11335fc10d2305a6673fd5f95b7a1a2e0b0c7f86..5df9f1a2b90d0f610bc8673b27e978b54ba7058e 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.db.component;
 
 import java.util.Locale;
 import java.util.Set;
+import java.util.stream.Stream;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.db.WildcardPosition;
@@ -35,6 +36,8 @@ public class ComponentQuery {
   private final String language;
   private final Boolean isPrivate;
   private final Set<Long> componentIds;
+  private final Set<String> componentUuids;
+  private final Set<String> componentKeys;
   private final Long analyzedBefore;
   private final boolean onProvisionedOnly;
 
@@ -44,6 +47,8 @@ public class ComponentQuery {
     this.qualifiers = builder.qualifiers;
     this.language = builder.language;
     this.componentIds = builder.componentIds;
+    this.componentUuids = builder.componentUuids;
+    this.componentKeys = builder.componentKeys;
     this.isPrivate = builder.isPrivate;
     this.analyzedBefore = builder.analyzedBefore;
     this.onProvisionedOnly = builder.onProvisionedOnly;
@@ -83,6 +88,16 @@ public class ComponentQuery {
     return componentIds;
   }
 
+  @CheckForNull
+  public Set<String> getComponentUuids() {
+    return componentUuids;
+  }
+
+  @CheckForNull
+  public Set<String> getComponentKeys() {
+    return componentKeys;
+  }
+
   @CheckForNull
   public Boolean getPrivate() {
     return isPrivate;
@@ -97,6 +112,11 @@ public class ComponentQuery {
     return onProvisionedOnly;
   }
 
+  boolean hasEmptySetOfComponents() {
+    return Stream.of(componentIds, componentKeys, componentUuids)
+      .anyMatch(list -> list != null && list.isEmpty());
+  }
+
   public static Builder builder() {
     return new Builder();
   }
@@ -108,6 +128,8 @@ public class ComponentQuery {
     private String language;
     private Boolean isPrivate;
     private Set<Long> componentIds;
+    private Set<String> componentUuids;
+    private Set<String> componentKeys;
     private Long analyzedBefore;
     private boolean onProvisionedOnly = false;
 
@@ -139,6 +161,16 @@ public class ComponentQuery {
       return this;
     }
 
+    public Builder setComponentUuids(@Nullable Set<String> componentUuids) {
+      this.componentUuids = componentUuids;
+      return this;
+    }
+
+    public Builder setComponentKeys(@Nullable Set<String> componentKeys) {
+      this.componentKeys = componentKeys;
+      return this;
+    }
+
     public Builder setPrivate(@Nullable Boolean isPrivate) {
       this.isPrivate = isPrivate;
       return this;
index 29c5724e0ad6a8488142e7a4df156dc2b97e201c..2f738fc26d2950cf44c0fba0d7de3f7e84dc808d 100644 (file)
           #{componentId,jdbcType=BIGINT}
         </foreach>
       </if>
+      <if test="query.componentKeys!=null">
+        and p.kee in
+        <foreach collection="query.componentKeys" item="componentKey" open="(" close=")" separator=",">
+          #{componentKey,jdbcType=BIGINT}
+        </foreach>
+      </if>
+      <if test="query.componentUuids!=null">
+        and p.uuid in
+        <foreach collection="query.componentUuids" item="componentUuid" open="(" close=")" separator=",">
+          #{componentUuid,jdbcType=BIGINT}
+        </foreach>
+      </if>
       <if test="query.nameOrKeyQuery!=null">
         and (
           upper(p.name) like #{query.nameOrKeyUpperLikeQuery,jdbcType=VARCHAR} escape '/'
index dd3c15cbd352425ce3bca16a29de9245d0c712a4..2050730e8fd0acdee932dad974260053a67250b4 100644 (file)
@@ -1034,7 +1034,9 @@ public class ComponentDaoTest {
 
   @Test
   public void selectByQuery_on_empty_list_of_component_id() {
+    db.components().insertPrivateProject();
     ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT).setComponentIds(emptySet()).build();
+
     List<ComponentDto> result = underTest.selectByQuery(dbSession, dbQuery, 0, 10);
     int count = underTest.countByQuery(dbSession, dbQuery);
 
@@ -1058,6 +1060,62 @@ public class ComponentDaoTest {
       .doesNotContain(cLang.getId());
   }
 
+  @Test
+  public void selectByQuery_on_empty_list_of_component_key() {
+    db.components().insertPrivateProject();
+    ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT).setComponentKeys(emptySet()).build();
+
+    List<ComponentDto> result = underTest.selectByQuery(dbSession, dbQuery, 0, 10);
+    int count = underTest.countByQuery(dbSession, dbQuery);
+
+    assertThat(result).isEmpty();
+    assertThat(count).isEqualTo(0);
+  }
+
+  @Test
+  public void selectByQuery_on_component_keys() {
+    OrganizationDto organizationDto = db.organizations().insert();
+    ComponentDto sonarqube = db.components().insertComponent(newPrivateProjectDto(organizationDto));
+    ComponentDto jdk8 = db.components().insertComponent(newPrivateProjectDto(organizationDto));
+    ComponentDto cLang = db.components().insertComponent(newPrivateProjectDto(organizationDto));
+    ComponentQuery query = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT)
+      .setComponentKeys(newHashSet(sonarqube.getDbKey(), jdk8.getDbKey())).build();
+
+    List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 0, 10);
+
+    assertThat(result).hasSize(2).extracting(ComponentDto::getDbKey)
+      .containsExactlyInAnyOrder(sonarqube.getDbKey(), jdk8.getDbKey())
+      .doesNotContain(cLang.getDbKey());
+  }
+
+  @Test
+  public void selectByQuery_on_empty_list_of_component_uuids() {
+    db.components().insertPrivateProject();
+    ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT).setComponentUuids(emptySet()).build();
+
+    List<ComponentDto> result = underTest.selectByQuery(dbSession, dbQuery, 0, 10);
+    int count = underTest.countByQuery(dbSession, dbQuery);
+
+    assertThat(result).isEmpty();
+    assertThat(count).isEqualTo(0);
+  }
+
+  @Test
+  public void selectByQuery_on_component_uuids() {
+    OrganizationDto organizationDto = db.organizations().insert();
+    ComponentDto sonarqube = db.components().insertComponent(newPrivateProjectDto(organizationDto));
+    ComponentDto jdk8 = db.components().insertComponent(newPrivateProjectDto(organizationDto));
+    ComponentDto cLang = db.components().insertComponent(newPrivateProjectDto(organizationDto));
+    ComponentQuery query = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT)
+      .setComponentUuids(newHashSet(sonarqube.uuid(), jdk8.uuid())).build();
+
+    List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 0, 10);
+
+    assertThat(result).hasSize(2).extracting(ComponentDto::uuid)
+      .containsOnlyOnce(sonarqube.uuid(), jdk8.uuid())
+      .doesNotContain(cLang.uuid());
+  }
+
   @Test
   public void selectAncestors() {
     // organization
index 018cec3f8b6b6b408f2a335fc074e5de68117108..58ab402170570cce2c771d892a3eca0a5febca00 100644 (file)
  */
 package org.sonar.db.component;
 
+import java.util.function.Supplier;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
+import static java.util.Collections.emptySet;
+import static java.util.Collections.singleton;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 
@@ -46,6 +49,7 @@ public class ComponentQueryTest {
     assertThat(underTest.getAnalyzedBefore()).isEqualTo(1_000_000_000L);
     assertThat(underTest.isOnProvisionedOnly()).isFalse();
     assertThat(underTest.isPartialMatchOnKey()).isFalse();
+    assertThat(underTest.hasEmptySetOfComponents()).isFalse();
   }
 
   @Test
@@ -69,6 +73,18 @@ public class ComponentQueryTest {
     assertThat(underTest.getNameOrKeyUpperLikeQuery()).isEqualTo("%NAME//KEY%");
   }
 
+  @Test
+  public void empty_list_of_components() {
+    Supplier<ComponentQuery.Builder> query = () -> ComponentQuery.builder().setQualifiers(PROJECT);
+
+    assertThat(query.get().setComponentIds(emptySet()).build().hasEmptySetOfComponents()).isTrue();
+    assertThat(query.get().setComponentKeys(emptySet()).build().hasEmptySetOfComponents()).isTrue();
+    assertThat(query.get().setComponentUuids(emptySet()).build().hasEmptySetOfComponents()).isTrue();
+    assertThat(query.get().setComponentIds(singleton(404L)).build().hasEmptySetOfComponents()).isFalse();
+    assertThat(query.get().setComponentKeys(singleton("P1")).build().hasEmptySetOfComponents()).isFalse();
+    assertThat(query.get().setComponentUuids(singleton("U1")).build().hasEmptySetOfComponents()).isFalse();
+  }
+
   @Test
   public void fail_if_no_qualifier_provided() {
     expectedException.expect(IllegalArgumentException.class);
index 815763caf679e72109c073fe466f792aa1844202..d7da8b0dc6f830ee723427d26a3dc7f696a27a37 100644 (file)
@@ -34,12 +34,12 @@ import org.sonar.server.user.UserSession;
 
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_IDS;
 
 public class BulkDeleteAction implements ProjectsWsAction {
 
   private static final String ACTION = "bulk_delete";
-  private static final String PARAM_PROJECT_IDS = "projectIds";
-  private static final String PARAM_PROJECTS = "projects";
 
   private final ComponentCleanerService componentCleanerService;
   private final DbClient dbClient;
index 4c68af58ebed65465ef3f2738dae03ed1d895225..ecbf987db9e6602bde8105a6f269a274dda68e8a 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.project.ws;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
@@ -50,8 +51,12 @@ import static org.sonar.api.resources.Qualifiers.VIEW;
 import static org.sonar.api.utils.DateUtils.formatDateTime;
 import static org.sonar.api.utils.DateUtils.parseDateOrDateTime;
 import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
 import static org.sonar.server.project.Visibility.PRIVATE;
 import static org.sonar.server.project.Visibility.PUBLIC;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.WsProjects.SearchWsResponse.Component;
 import static org.sonarqube.ws.WsProjects.SearchWsResponse.newBuilder;
@@ -60,6 +65,8 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.MAX_PAGE_SIZE
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_IDS;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
 
@@ -121,6 +128,20 @@ public class SearchAction implements ProjectsWsAction {
       .setBooleanPossibleValues()
       .setDefaultValue("false")
       .setSince("6.6");
+
+    action
+      .createParam(PARAM_PROJECTS)
+      .setDescription("Comma-separated list of project keys")
+      .setSince("6.6")
+      .setExampleValue(String.join(",", KEY_PROJECT_EXAMPLE_001, KEY_PROJECT_EXAMPLE_002));
+
+    action
+      .createParam(PARAM_PROJECT_IDS)
+      .setDescription("Comma-separated list of project ids")
+      .setSince("6.6")
+      // parameter added to match api/projects/bulk_delete parameters
+      .setDeprecatedSince("6.6")
+      .setExampleValue(String.join(",", UUID_EXAMPLE_01, UUID_EXAMPLE_02));
   }
 
   @Override
@@ -139,6 +160,8 @@ public class SearchAction implements ProjectsWsAction {
       .setVisibility(request.param(PARAM_VISIBILITY))
       .setAnalyzedBefore(request.param(PARAM_ANALYZED_BEFORE))
       .setOnProvisionedOnly(request.mandatoryParamAsBoolean(PARAM_ON_PROVISIONED_ONLY))
+      .setProjects(request.paramAsStrings(PARAM_PROJECTS))
+      .setProjectIds(request.paramAsStrings(PARAM_PROJECT_IDS))
       .build();
   }
 
@@ -147,7 +170,7 @@ public class SearchAction implements ProjectsWsAction {
       OrganizationDto organization = support.getOrganization(dbSession, ofNullable(request.getOrganization()).orElseGet(defaultOrganizationProvider.get()::getKey));
       userSession.checkPermission(OrganizationPermission.ADMINISTER, organization);
 
-      ComponentQuery query = buildQuery(request);
+      ComponentQuery query = buildDbQuery(request);
       Paging paging = buildPaging(dbSession, request, organization, query);
       List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), query, paging.offset(), paging.pageSize());
       Map<String, Long> analysisDateByComponentUuid = dbClient.snapshotDao()
@@ -157,7 +180,7 @@ public class SearchAction implements ProjectsWsAction {
     }
   }
 
-  private static ComponentQuery buildQuery(SearchWsRequest request) {
+  private static ComponentQuery buildDbQuery(SearchWsRequest request) {
     List<String> qualifiers = request.getQualifiers();
     ComponentQuery.Builder query = ComponentQuery.builder()
       .setQualifiers(qualifiers.toArray(new String[qualifiers.size()]));
@@ -170,6 +193,8 @@ public class SearchAction implements ProjectsWsAction {
     setNullable(request.getVisibility(), v -> query.setPrivate(Visibility.isPrivate(v)));
     setNullable(request.getAnalyzedBefore(), d -> query.setAnalyzedBefore(parseDateOrDateTime(d).getTime()));
     setNullable(request.isOnProvisionedOnly(), query::setOnProvisionedOnly);
+    setNullable(request.getProjects(), keys -> query.setComponentKeys(new HashSet<>(keys)));
+    setNullable(request.getProjectIds(), uuids -> query.setComponentUuids(new HashSet<>(uuids)));
 
     return query.build();
   }
index 1e0ea685dda6d5f9cacb506fc6c5673646697eea..40cf88ca7c1d88f4a52b1dc86c34a2cba07fa61f 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.base.Joiner;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 import org.assertj.core.api.Assertions;
@@ -71,6 +72,8 @@ import static org.sonar.test.JsonAssert.assertJson;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_IDS;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
 
 public class SearchActionTest {
@@ -258,6 +261,38 @@ public class SearchActionTest {
       .doesNotContain(analyzedProject.getKey());
   }
 
+  @Test
+  public void search_by_component_keys() {
+    userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
+    ComponentDto jdk = db.components().insertPrivateProject();
+    ComponentDto sonarqube = db.components().insertPrivateProject();
+    ComponentDto sonarlint = db.components().insertPrivateProject();
+
+    SearchWsResponse result = call(SearchWsRequest.builder()
+      .setProjects(Arrays.asList(jdk.getKey(), sonarqube.getKey()))
+      .build());
+
+    assertThat(result.getComponentsList()).extracting(Component::getKey)
+      .containsExactlyInAnyOrder(jdk.getKey(), sonarqube.getKey())
+      .doesNotContain(sonarlint.getKey());
+  }
+
+  @Test
+  public void search_by_component_uuids() {
+    userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
+    ComponentDto jdk = db.components().insertPrivateProject();
+    ComponentDto sonarqube = db.components().insertPrivateProject();
+    ComponentDto sonarlint = db.components().insertPrivateProject();
+
+    SearchWsResponse result = call(SearchWsRequest.builder()
+      .setProjectIds(Arrays.asList(jdk.uuid(), sonarqube.uuid()))
+      .build());
+
+    assertThat(result.getComponentsList()).extracting(Component::getKey)
+      .containsExactlyInAnyOrder(jdk.getKey(), sonarqube.getKey())
+      .doesNotContain(sonarlint.getKey());
+  }
+
   @Test
   public void fail_when_not_system_admin() throws Exception {
     userSession.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
@@ -291,8 +326,8 @@ public class SearchActionTest {
     assertThat(action.isInternal()).isFalse();
     assertThat(action.since()).isEqualTo("6.3");
     assertThat(action.handler()).isEqualTo(ws.getDef().handler());
-    assertThat(action.params()).hasSize(8).extracting(Param::key)
-      .containsExactlyInAnyOrder("organization", "q", "qualifiers", "p", "ps", "visibility", "analyzedBefore", "onProvisionedOnly");
+    assertThat(action.params()).extracting(Param::key)
+      .containsExactlyInAnyOrder("organization", "q", "qualifiers", "p", "ps", "visibility", "analyzedBefore", "onProvisionedOnly", "projects", "projectIds");
     assertThat(action.responseExample()).isEqualTo(getClass().getResource("search-example.json"));
 
     Param organization = action.param("organization");
@@ -374,6 +409,8 @@ public class SearchActionTest {
     setNullable(wsRequest.getPageSize(), pageSize -> request.setParam(PAGE_SIZE, String.valueOf(pageSize)));
     setNullable(wsRequest.getVisibility(), v -> request.setParam(PARAM_VISIBILITY, v));
     setNullable(wsRequest.getAnalyzedBefore(), d -> request.setParam(PARAM_ANALYZED_BEFORE, d));
+    setNullable(wsRequest.getProjects(), l -> request.setParam(PARAM_PROJECTS, String.join(",", l)));
+    setNullable(wsRequest.getProjectIds(), l -> request.setParam(PARAM_PROJECT_IDS, String.join(",", l)));
     request.setParam(PARAM_ON_PROVISIONED_ONLY, String.valueOf(wsRequest.isOnProvisionedOnly()));
     return request.executeProtobuf(SearchWsResponse.class);
   }
index a3acd885cdfc58b5b3578ad74d2f6483109a3324..6ebe8424074559cd2f29336a9cec71ceb4565d58 100644 (file)
@@ -44,7 +44,9 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ON_PROVISIONED_ONLY;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECTS;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_ID;
+import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT_IDS;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_TO;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
@@ -118,7 +120,9 @@ public class ProjectsService extends BaseService {
       .setParam(TEXT_QUERY, request.getQuery())
       .setParam(PAGE, request.getPage())
       .setParam(PAGE_SIZE, request.getPageSize())
-      .setParam(PARAM_ON_PROVISIONED_ONLY, request.isOnProvisionedOnly());
+      .setParam(PARAM_ON_PROVISIONED_ONLY, request.isOnProvisionedOnly())
+      .setParam(PARAM_PROJECTS, request.getProjects())
+      .setParam(PARAM_PROJECT_IDS, request.getProjectIds());
     return call(get, SearchWsResponse.parser());
   }
 
index 131c6465645c586845efc611a17d5f07424e5dfd..c6a8bb1c32652bbb683cfddf95db84da7527bc04 100644 (file)
@@ -44,6 +44,8 @@ public class ProjectsWsParameters {
   public static final String PARAM_VISIBILITY = "visibility";
   public static final String PARAM_ANALYZED_BEFORE = "analyzedBefore";
   public static final String PARAM_ON_PROVISIONED_ONLY = "onProvisionedOnly";
+  public static final String PARAM_PROJECT_IDS = "projectIds";
+  public static final String PARAM_PROJECTS = "projects";
 
   public static final String FILTER_LANGUAGES = "languages";
   public static final String FILTER_TAGS = "tags";
index 04d0e8d4fceb95c7d00274eb1e28c79e5c5d4391..422bb90f6d9df4cabf50a2fd4e318f4cd05c2a9d 100644 (file)
@@ -38,6 +38,8 @@ public class SearchWsRequest {
   private final Integer pageSize;
   private final String analyzedBefore;
   private final boolean onProvisionedOnly;
+  private final List<String> projects;
+  private final List<String> projectIds;
 
   public SearchWsRequest(Builder builder) {
     this.organization = builder.organization;
@@ -48,6 +50,8 @@ public class SearchWsRequest {
     this.pageSize = builder.pageSize;
     this.analyzedBefore = builder.analyzedBefore;
     this.onProvisionedOnly = builder.onProvisionedOnly;
+    this.projects = builder.projects;
+    this.projectIds = builder.projectIds;
   }
 
   @CheckForNull
@@ -88,6 +92,16 @@ public class SearchWsRequest {
     return onProvisionedOnly;
   }
 
+  @CheckForNull
+  public List<String> getProjects() {
+    return projects;
+  }
+
+  @CheckForNull
+  public List<String> getProjectIds() {
+    return projectIds;
+  }
+
   public static Builder builder() {
     return new Builder();
   }
@@ -101,6 +115,8 @@ public class SearchWsRequest {
     private String visibility;
     private String analyzedBefore;
     private boolean onProvisionedOnly = false;
+    private List<String> projects;
+    private List<String> projectIds;
 
     public Builder setOrganization(@Nullable String organization) {
       this.organization = organization;
@@ -142,7 +158,19 @@ public class SearchWsRequest {
       return this;
     }
 
+    public Builder setProjects(@Nullable List<String> projects) {
+      this.projects = projects;
+      return this;
+    }
+
+    public Builder setProjectIds(@Nullable List<String> projectIds) {
+      this.projectIds = projectIds;
+      return this;
+    }
+
     public SearchWsRequest build() {
+      checkArgument(projects==null || !projects.isEmpty(), "Project key list must not be empty");
+      checkArgument(projectIds==null || !projectIds.isEmpty(), "Project id list must not be empty");
       checkArgument(pageSize == null || pageSize <= MAX_PAGE_SIZE, "Page size must not be greater than %s", MAX_PAGE_SIZE);
       return new SearchWsRequest(this);
     }
index 89f27374b0ab60b0b8511b6cd5538a99378bb2da..121a6d5b07515aef79049a53e812a62879de7223 100644 (file)
@@ -24,6 +24,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
 import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class SearchWsRequestTest {
@@ -57,4 +58,24 @@ public class SearchWsRequestTest {
       .setPageSize(10000)
       .build();
   }
+
+  @Test
+  public void fail_if_project_key_list_is_empty() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Project key list must not be empty");
+
+    SearchWsRequest.builder()
+      .setProjects(emptyList())
+      .build();
+  }
+
+  @Test
+  public void fail_if_project_id_list_is_empty() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Project id list must not be empty");
+
+    SearchWsRequest.builder()
+      .setProjectIds(emptyList())
+      .build();
+  }
 }
index 4882176d56759d75b79a7f5acbce2f58cc26640e..23313f49d1d48b48da43e1ff83d73c68a35c941f 100644 (file)
@@ -68,7 +68,7 @@ public class ProjectSearchTest {
   }
 
   @Test
-  public void search_on_key_partial_match_case_insensitive() {
+  public void search_on_key_query_partial_match_case_insensitive() {
     Organizations.Organization organization = tester.organizations().generate();
     CreateWsResponse.Project lowerCaseProject = tester.projects().generate(organization, p -> p.setKey("project-key"));
     CreateWsResponse.Project upperCaseProject = tester.projects().generate(organization, p -> p.setKey("PROJECT-KEY"));