From f4c2e0eb9afe66f5e71e9f1447f059dd15b143ff 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 --- .../org/sonar/db/component/ComponentDto.java | 17 ++++++++++++++ .../sonar/db/component/ComponentMapper.xml | 7 ++++-- .../sonar/db/component/ComponentDaoTest.java | 21 ++++++++++++++++- .../server/component/ws/SearchAction.java | 3 ++- .../ws/search-components-example.json | 12 ++++++---- .../server/component/ws/SearchActionTest.java | 23 ++++++++++++++++++- .../src/main/protobuf/ws-components.proto | 2 ++ 7 files changed, 76 insertions(+), 9 deletions(-) diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java index 215a248c0c4..797dfb1f57a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDto.java @@ -60,6 +60,11 @@ public class ComponentDto implements Component { */ private String kee; + /** + * Key of the root component this component belongs to. Consistent with projectUUid. + */ + private String projectKey; + /** * Not empty . Max size is 50 (note that effective UUID values are 40 characters with * the current algorithm in use). Obviously it is unique. @@ -221,6 +226,18 @@ public class ComponentDto implements Component { return this; } + /** + * Return the root project key. On a root project, return itself + */ + public String projectKey() { + return projectKey; + } + + public ComponentDto setProjectKey(String projectKey) { + this.projectKey = projectKey; + return this; + } + public boolean isRoot() { return UUID_PATH_OF_ROOT.equals(uuidPath); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml index fecf8cf8715..b9939aabb1c 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -238,18 +238,21 @@ - from projects p where p.enabled=${_true} AND p.copy_component_uuid is null diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java index c9c83436a8e..997131fb86b 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java @@ -47,6 +47,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; 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.assertj.guava.api.Assertions.assertThat; import static org.sonar.db.component.ComponentTesting.newDirectory; import static org.sonar.db.component.ComponentTesting.newFileDto; @@ -547,7 +548,8 @@ public class ComponentDaoTest { @Test public void select_provisioned() { OrganizationDto organization = db.organizations().insert(); - ComponentDto provisionedProject = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(organization).setKey("provisioned.project").setName("Provisioned Project")); + ComponentDto provisionedProject = db.components() + .insertComponent(ComponentTesting.newPrivateProjectDto(organization).setKey("provisioned.project").setName("Provisioned Project")); ComponentDto provisionedView = db.components().insertView(organization); String projectUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization)).getComponentUuid(); String disabledProjectUuid = db.components().insertProjectAndSnapshot(ComponentTesting.newPrivateProjectDto(organization).setEnabled(false)).getComponentUuid(); @@ -966,6 +968,23 @@ public class ComponentDaoTest { assertThat(underTest.selectByQuery(dbSession, allProjectsQuery, 0, 10)).extracting(ComponentDto::getKey).containsOnly("public-key", "private-key"); } + @Test + public void selectByQuery_returns_projectKey() { + ComponentDto project = ComponentTesting.newPublicProjectDto(db.getDefaultOrganization()).setKey("project-key"); + db.components().insertComponent(project); + ComponentDto module = ComponentTesting.newModuleDto(project).setKey("module-key"); + db.components().insertComponent(module); + ComponentDto file = ComponentTesting.newFileDto(module).setKey("file-key"); + db.components().insertComponent(file); + + ComponentQuery allQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT, Qualifiers.MODULE, Qualifiers.FILE).build(); + + assertThat(underTest.selectByQuery(dbSession, allQuery, 0, 10)).extracting(ComponentDto::getKey, ComponentDto::projectKey) + .containsOnly(tuple("project-key", "project-key"), + tuple("module-key", "project-key"), + tuple("file-key", "project-key")); + } + @Test public void selectByQuery_on_empty_list_of_component_id() { ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT).setComponentIds(emptySet()).build(); 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..b26ae50b54c 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 @@ -46,8 +46,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.core.util.Protobuf.setNullable; 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; @@ -179,6 +179,7 @@ public class SearchAction implements ComponentsWsAction { .setOrganization(organization.getKey()) .setId(dto.uuid()) .setKey(dto.key()) + .setProjectKey(dto.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..8f86a13f6ed 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", + "projectKey": "project-key" }, { "organization": "my-org-1", @@ -18,21 +19,24 @@ "key": "file-key", "qualifier": "FIL", "name": "File Name", - "language": "java" + "language": "java", + "projectKey": "project-key" }, { "organization": "my-org-1", "id": "module-uuid", "key": "module-key", "qualifier": "BRC", - "name": "Module Name" + "name": "Module Name", + "projectKey": "project-key" }, { "organization": "my-org-1", "id": "project-uuid", "key": "project-key", "qualifier": "TRK", - "name": "Project Name" + "name": "Project Name", + "projectKey": "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..ac1651bc67d 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::getProjectKey) + .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..4a7fe369ced 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 projectKey = 17; message Tags { repeated string tags = 1; -- 2.39.5