From 1930b52f3a1d5441ae786417506a8cd21ce3b796 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Wed, 26 Jul 2017 17:48:32 +0200 Subject: [PATCH] SONAR-9584 Add root project key to response of api/components/search --- .../server/component/ws/SearchAction.java | 24 +++++++++++++++---- .../ws/search-components-example.json | 12 ++++++---- .../server/component/ws/SearchActionTest.java | 23 +++++++++++++++++- .../src/main/protobuf/ws-components.proto | 2 ++ 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java index 658de71faa9..1674f6de9e2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java @@ -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 components = searchComponents(dbSession, organization, query, paging); + Map projectKeysByUuids = searchProjectsKeysByUuids(dbSession, components); - return buildResponse(components, organization, paging); + return buildResponse(components, organization, projectKeysByUuids, paging); } } + private Map searchProjectsKeysByUuids(DbSession dbSession, List components) { + Set projectUuidsToSearch = components.stream() + .map(ComponentDto::projectUuid) + .collect(toHashSet()); + List projects = dbClient.componentDao().selectByUuids(dbSession, projectUuidsToSearch); + return projects.stream().collect(toMap(ComponentDto::uuid, ComponentDto::key)); + } + private static ComponentQuery buildQuery(SearchWsRequest request) { List 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 components, OrganizationDto organization, Paging paging) { + private static SearchWsResponse buildResponse(List components, OrganizationDto organization, Map 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); diff --git a/server/sonar-server/src/main/resources/org/sonar/server/component/ws/search-components-example.json b/server/sonar-server/src/main/resources/org/sonar/server/component/ws/search-components-example.json index dafce933828..4811ba96637 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/component/ws/search-components-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/component/ws/search-components-example.json @@ -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", @@ -18,21 +19,24 @@ "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" } ] } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java index 0a22c4c68da..1563d32fd9f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java @@ -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(); diff --git a/sonar-ws/src/main/protobuf/ws-components.proto b/sonar-ws/src/main/protobuf/ws-components.proto index 58b02d9687c..eba01af28f6 100644 --- a/sonar-ws/src/main/protobuf/ws-components.proto +++ b/sonar-ws/src/main/protobuf/ws-components.proto @@ -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; -- 2.39.5