]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9584 Add root project key to response of api/components/search
authorJulien HENRY <julien.henry@sonarsource.com>
Wed, 26 Jul 2017 15:48:32 +0000 (17:48 +0200)
committerJulien HENRY <julien.henry@sonarsource.com>
Thu, 27 Jul 2017 10:12:43 +0000 (12:12 +0200)
server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java
server/sonar-server/src/main/resources/org/sonar/server/component/ws/search-components-example.json
server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java
sonar-ws/src/main/protobuf/ws-components.proto

index 658de71faa9867ea44410530b2d291a37ad32851..1674f6de9e2f36f18af655b3112efe0d52dc50e2 100644 (file)
@@ -20,7 +20,9 @@
 package org.sonar.server.component.ws;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.ResourceTypes;
@@ -43,11 +45,13 @@ import org.sonarqube.ws.WsComponents.SearchWsResponse;
 import org.sonarqube.ws.client.component.SearchWsRequest;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.stream.Collectors.toMap;
 import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.core.util.stream.MoreCollectors.toHashSet;
 import static org.sonar.server.util.LanguageParamUtils.getExampleValue;
 import static org.sonar.server.util.LanguageParamUtils.getLanguageKeys;
-import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
 import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter;
+import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_SEARCH;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_LANGUAGE;
@@ -120,11 +124,20 @@ public class SearchAction implements ComponentsWsAction {
       OrganizationDto organization = getOrganization(dbSession, request);
       Paging paging = buildPaging(dbSession, request, organization, query);
       List<ComponentDto> components = searchComponents(dbSession, organization, query, paging);
+      Map<String, String> projectKeysByUuids = searchProjectsKeysByUuids(dbSession, components);
 
-      return buildResponse(components, organization, paging);
+      return buildResponse(components, organization, projectKeysByUuids, paging);
     }
   }
 
+  private Map<String, String> searchProjectsKeysByUuids(DbSession dbSession, List<ComponentDto> components) {
+    Set<String> projectUuidsToSearch = components.stream()
+      .map(ComponentDto::projectUuid)
+      .collect(toHashSet());
+    List<ComponentDto> projects = dbClient.componentDao().selectByUuids(dbSession, projectUuidsToSearch);
+    return projects.stream().collect(toMap(ComponentDto::uuid, ComponentDto::key));
+  }
+
   private static ComponentQuery buildQuery(SearchWsRequest request) {
     List<String> qualifiers = request.getQualifiers();
     return ComponentQuery.builder()
@@ -154,7 +167,7 @@ public class SearchAction implements ComponentsWsAction {
     return userSession.keepAuthorizedComponents(UserRole.USER, componentDtos);
   }
 
-  private static SearchWsResponse buildResponse(List<ComponentDto> components, OrganizationDto organization, Paging paging) {
+  private static SearchWsResponse buildResponse(List<ComponentDto> components, OrganizationDto organization, Map<String, String> projectKeysByUuids, Paging paging) {
     SearchWsResponse.Builder responseBuilder = SearchWsResponse.newBuilder();
     responseBuilder.getPagingBuilder()
       .setPageIndex(paging.pageIndex())
@@ -163,13 +176,13 @@ public class SearchAction implements ComponentsWsAction {
       .build();
 
     components.stream()
-      .map(dto -> dtoToComponent(organization, dto))
+      .map(dto -> dtoToComponent(organization, dto, projectKeysByUuids.get(dto.projectUuid())))
       .forEach(responseBuilder::addComponents);
 
     return responseBuilder.build();
   }
 
-  private static WsComponents.Component dtoToComponent(OrganizationDto organization, ComponentDto dto) {
+  private static WsComponents.Component dtoToComponent(OrganizationDto organization, ComponentDto dto, String projectKey) {
     checkArgument(
       organization.getUuid().equals(dto.getOrganizationUuid()),
       "No Organization found for uuid '%s'",
@@ -179,6 +192,7 @@ public class SearchAction implements ComponentsWsAction {
       .setOrganization(organization.getKey())
       .setId(dto.uuid())
       .setKey(dto.key())
+      .setProject(projectKey)
       .setName(dto.name())
       .setQualifier(dto.qualifier());
     setNullable(dto.language(), builder::setLanguage);
index dafce93382832c6fb9fa17daf68c886d06e36377..4811ba96637c706a192ebd1d61cb2fc131e9550a 100644 (file)
@@ -10,7 +10,8 @@
       "id": "directory-uuid",
       "key": "directory-key",
       "qualifier": "DIR",
-      "name": "Directory Name"
+      "name": "Directory Name",
+      "project": "project-key"
     },
     {
       "organization": "my-org-1",
       "key": "file-key",
       "qualifier": "FIL",
       "name": "File Name",
-      "language": "java"
+      "language": "java",
+      "project": "project-key"
     },
     {
       "organization": "my-org-1",
       "id": "module-uuid",
       "key": "module-key",
       "qualifier": "BRC",
-      "name": "Module Name"
+      "name": "Module Name",
+      "project": "project-key"
     },
     {
       "organization": "my-org-1",
       "id": "project-uuid",
       "key": "project-key",
       "qualifier": "TRK",
-      "name": "Project Name"
+      "name": "Project Name",
+      "project": "project-key"
     }
   ]
 }
index 0a22c4c68da69bd8df8adb9d7e34d1218562e27b..1563d32fd9f89661cd4f02fd15df61b0fe7066f3 100644 (file)
@@ -45,11 +45,14 @@ import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
 import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.WsComponents.Component;
 import org.sonarqube.ws.WsComponents.SearchWsResponse;
 import org.sonarqube.ws.client.component.SearchWsRequest;
 
+import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.sonar.api.resources.Qualifiers.DIRECTORY;
@@ -66,7 +69,6 @@ import static org.sonar.db.component.ComponentTesting.newModuleDto;
 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
 import static org.sonar.db.component.ComponentTesting.newView;
 import static org.sonar.test.JsonAssert.assertJson;
-import static org.sonarqube.ws.WsComponents.Component;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_LANGUAGE;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS;
@@ -185,6 +187,25 @@ public class SearchActionTest {
     assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(file1.getKey(), file2.getKey());
   }
 
+  @Test
+  public void return_project_key() throws IOException {
+    ComponentDto project = ComponentTesting.newPublicProjectDto(db.getDefaultOrganization());
+    ComponentDto module = ComponentTesting.newModuleDto(project);
+    ComponentDto file1 = newFileDto(module).setKey("file1");
+    ComponentDto file2 = newFileDto(module).setKey("file2");
+    ComponentDto file3 = newFileDto(project).setKey("file3");
+    db.components().insertComponents(project, module, file1, file2, file3);
+
+    SearchWsResponse response = call(new SearchWsRequest().setQualifiers(asList(PROJECT, MODULE, FILE)));
+
+    assertThat(response.getComponentsList()).extracting(Component::getKey, Component::getProject)
+      .containsOnly(tuple(project.getKey(), project.getKey()),
+        tuple(module.getKey(), project.getKey()),
+        tuple(file1.getKey(), project.getKey()),
+        tuple(file2.getKey(), project.getKey()),
+        tuple(file3.getKey(), project.getKey()));
+  }
+
   @Test
   public void do_not_verify_permissions_if_user_is_root() throws IOException {
     OrganizationDto org = db.organizations().insert();
index 58b02d9687c265f9efbb7eb61e62c79444a033e4..eba01af28f6454fa1cacccaffb9ad38b7ede022b 100644 (file)
@@ -118,6 +118,8 @@ message Component {
   optional Tags tags = 14;
   optional string visibility = 15;
   optional string leakPeriodDate = 16;
+  // Root project key
+  optional string project = 17;
 
   message Tags {
     repeated string tags = 1;