From a6088983a2146ab1ef8bc1f942127ec1b203309e Mon Sep 17 00:00:00 2001 From: Benjamin Campomenosi <109955405+benjamin-campomenosi-sonarsource@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:12:04 +0200 Subject: [PATCH] SONAR-19256 refactor project links to use entity --- .../step/PersistProjectLinksStepIT.java | 50 +++++----- .../steps/ExportLinksStepIT.java | 42 +++----- .../step/PersistProjectLinksStep.java | 14 +-- .../sonar/db/component/ProjectLinkDaoIT.java | 55 +++++------ .../org/sonar/db/project/ProjectDaoIT.java | 26 +++++ .../it/java/org/sonar/db/user/RoleDaoIT.java | 16 +++- .../java/org/sonar/db/project/ProjectDao.java | 8 ++ .../org/sonar/db/project/ProjectMapper.java | 3 + .../main/java/org/sonar/db/user/RoleDao.java | 7 +- .../java/org/sonar/db/user/RoleMapper.java | 4 +- .../org/sonar/db/project/ProjectMapper.xml | 13 +++ .../org/sonar/db/user/RoleMapper.xml | 52 +++++----- .../java/org/sonar/db/DbTester.java | 8 +- .../db/component/ProjectLinkDbTester.java | 20 +--- .../project/ws/SearchMyProjectsActionIT.java | 96 ++++++++++--------- .../server/projectlink/ws/DeleteActionIT.java | 36 +++---- .../server/projectlink/ws/SearchActionIT.java | 51 +++++----- .../project/ws/SearchMyProjectsAction.java | 80 ++++++++++------ .../project/ws/SearchMyProjectsData.java | 37 ++++++- .../project/ws/SearchMyProjectsDataTest.java | 6 +- 20 files changed, 359 insertions(+), 265 deletions(-) diff --git a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistProjectLinksStepIT.java b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistProjectLinksStepIT.java index 5f35be87610..c0469bda4b8 100644 --- a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistProjectLinksStepIT.java +++ b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectanalysis/step/PersistProjectLinksStepIT.java @@ -19,6 +19,7 @@ */ package org.sonar.ce.task.projectanalysis.step; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.Mockito; @@ -37,10 +38,11 @@ import org.sonar.core.util.UuidFactory; import org.sonar.core.util.UuidFactoryFast; import org.sonar.db.DbClient; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ProjectData; import org.sonar.db.component.ProjectLinkDto; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; +import org.sonar.server.project.Project; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -64,6 +66,8 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Rule public BatchReportReaderRule reportReader = new BatchReportReaderRule(); + private ProjectData project; + private PersistProjectLinksStep underTest = new PersistProjectLinksStep(analysisMetadataHolder, db.getDbClient(), treeRootHolder, reportReader, UuidFactoryFast.getInstance()); @Override @@ -71,6 +75,12 @@ public class PersistProjectLinksStepIT extends BaseStepTest { return underTest; } + @Before + public void setup(){ + this.project = db.components().insertPrivateProject(); + analysisMetadataHolder.setProject(Project.fromProjectDtoWithTags(project.getProjectDto())); + } + @Test public void no_effect_if_branch_is_not_main() { DbClient dbClient = mock(DbClient.class); @@ -88,8 +98,7 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Test public void add_links_on_project() { mockBranch(true); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build()); - + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(project.getMainBranchComponent().uuid()).build()); // project reportReader.putComponent(ScannerReport.Component.newBuilder() .setRef(1) @@ -103,7 +112,7 @@ public class PersistProjectLinksStepIT extends BaseStepTest { underTest.execute(new TestComputationStepContext()); - assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), "ABCD")) + assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), project.projectUuid())) .extracting(ProjectLinkDto::getType, ProjectLinkDto::getHref, ProjectLinkDto::getName) .containsExactlyInAnyOrder( tuple("homepage", "http://www.sonarqube.org", null), @@ -115,10 +124,9 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Test public void nothing_to_do_when_link_already_exists() { mockBranch(true); - ComponentDto project = db.components().insertPrivateProject(p -> p.setUuid("ABCD")).getMainBranchComponent(); - db.componentLinks().insertProvidedLink(project, l -> l.setType("homepage").setName("Home").setHref("http://www.sonarqube.org")); + db.projectLinks().insertProvidedLink(project.getProjectDto(), l -> l.setType("homepage").setName("Home").setHref("http://www.sonarqube.org")); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build()); + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(project.getMainBranchComponent().uuid()).build()); reportReader.putComponent(ScannerReport.Component.newBuilder() .setRef(1) @@ -128,7 +136,7 @@ public class PersistProjectLinksStepIT extends BaseStepTest { underTest.execute(new TestComputationStepContext()); - assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), "ABCD")) + assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), project.projectUuid())) .extracting(ProjectLinkDto::getType, ProjectLinkDto::getHref) .containsExactlyInAnyOrder(tuple("homepage", "http://www.sonarqube.org")); } @@ -136,7 +144,7 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Test public void do_not_add_links_on_module() { mockBranch(true); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build()); + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(project.getMainBranchComponent().uuid()).build()); reportReader.putComponent(ScannerReport.Component.newBuilder() .setRef(1) .setType(ComponentType.PROJECT) @@ -156,7 +164,7 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Test public void do_not_add_links_on_file() { mockBranch(true); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").addChildren( + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(project.getMainBranchComponent().uuid()).addChildren( ReportComponent.builder(Component.Type.FILE, 2).setUuid("BCDE").build()) .build()); @@ -179,10 +187,8 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Test public void update_link() { mockBranch(true); - ComponentDto project = db.components().insertPrivateProject(p -> p.setUuid("ABCD")).getMainBranchComponent(); - db.componentLinks().insertProvidedLink(project, l -> l.setType("homepage").setName("Home").setHref("http://www.sonar.org")); - - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build()); + analysisMetadataHolder.setProject(Project.fromProjectDtoWithTags(project.getProjectDto())); + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(project.getMainBranchComponent().uuid()).build()); reportReader.putComponent(ScannerReport.Component.newBuilder() .setRef(1) @@ -192,7 +198,7 @@ public class PersistProjectLinksStepIT extends BaseStepTest { underTest.execute(new TestComputationStepContext()); - assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), "ABCD")) + assertThat(db.getDbClient().projectLinkDao().selectByProjectUuid(db.getSession(), project.getProjectDto().getUuid())) .extracting(ProjectLinkDto::getType, ProjectLinkDto::getHref) .containsExactlyInAnyOrder(tuple("homepage", "http://www.sonarqube.org")); } @@ -200,10 +206,9 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Test public void delete_link() { mockBranch(true); - ComponentDto project = db.components().insertPrivateProject(p -> p.setUuid("ABCD")).getMainBranchComponent(); - db.componentLinks().insertProvidedLink(project, l -> l.setType("homepage").setName("Home").setHref("http://www.sonar.org")); + db.projectLinks().insertProvidedLink(project.getProjectDto(), l -> l.setType("homepage").setName("Home").setHref("http://www.sonar.org")); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build()); + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(project.getMainBranchComponent().uuid()).build()); reportReader.putComponent(ScannerReport.Component.newBuilder() .setRef(1) @@ -218,10 +223,9 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Test public void not_delete_custom_link() { mockBranch(true); - ComponentDto project = db.components().insertPrivateProject(p -> p.setUuid("ABCD")).getMainBranchComponent(); - db.componentLinks().insertCustomLink(project); + db.projectLinks().insertCustomLink(project.getProjectDto()); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build()); + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(project.getMainBranchComponent().uuid()).build()); reportReader.putComponent(ScannerReport.Component.newBuilder() .setRef(1) @@ -236,7 +240,7 @@ public class PersistProjectLinksStepIT extends BaseStepTest { @Test public void fail_when_trying_to_add_same_link_type_multiple_times() { mockBranch(true); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").build()); + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(project.getMainBranchComponent().uuid()).build()); reportReader.putComponent(ScannerReport.Component.newBuilder() .setRef(1) @@ -247,7 +251,7 @@ public class PersistProjectLinksStepIT extends BaseStepTest { assertThatThrownBy(() -> underTest.execute(new TestComputationStepContext())) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Link of type 'homepage' has already been declared on component 'ABCD'"); + .hasMessage("Link of type 'homepage' has already been declared on component '%s'".formatted(project.projectUuid())); } private void mockBranch(boolean isMain) { diff --git a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/steps/ExportLinksStepIT.java b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/steps/ExportLinksStepIT.java index 117e24e288b..693621a22ff 100644 --- a/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/steps/ExportLinksStepIT.java +++ b/server/sonar-ce-task-projectanalysis/src/it/java/org/sonar/ce/task/projectexport/steps/ExportLinksStepIT.java @@ -24,14 +24,11 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.slf4j.event.Level; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Scopes; import org.sonar.api.testfixtures.log.LogTester; import org.sonar.api.utils.System2; -import org.sonar.ce.task.projectexport.component.ComponentRepository; import org.sonar.ce.task.step.TestComputationStepContext; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ProjectData; import org.sonar.db.component.ProjectLinkDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.project.ProjectExportMapper; @@ -41,40 +38,29 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.groups.Tuple.tuple; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT; public class ExportLinksStepIT { private static final String PROJECT_UUID = "project_uuid"; - private static final ComponentDto PROJECT = new ComponentDto() - // no id yet - .setScope(Scopes.PROJECT) - .setQualifier(Qualifiers.PROJECT) - .setKey("the_project") - .setName("The Project") - .setDescription("The project description") - .setEnabled(true) - .setUuid(PROJECT_UUID) - .setUuidPath(UUID_PATH_OF_ROOT) - .setBranchUuid(PROJECT_UUID); + + private ProjectDto projectDto; @Rule public DbTester db = DbTester.createWithExtensionMappers(System2.INSTANCE, true, ProjectExportMapper.class); - @Rule public LogTester logTester = new LogTester(); private final FakeDumpWriter dumpWriter = new FakeDumpWriter(); private final ProjectHolder projectHolder = mock(ProjectHolder.class); private final ExportLinksStep underTest = new ExportLinksStep(db.getDbClient(), projectHolder, dumpWriter); - private ProjectDto project; @Before public void setUp() { logTester.setLevel(Level.DEBUG); - project = db.components().insertPublicProject(PROJECT).getProjectDto(); - when(projectHolder.projectDto()).thenReturn(project); + ProjectData project = db.components().insertPublicProject(PROJECT_UUID); + this.projectDto = project.getProjectDto(); + when(projectHolder.projectDto()).thenReturn(projectDto); } @Test @@ -87,9 +73,9 @@ public class ExportLinksStepIT { @Test public void export_links() { - ProjectLinkDto link1 = db.componentLinks().insertCustomLink(project); - ProjectLinkDto link2 = db.componentLinks().insertProvidedLink(project); - db.componentLinks().insertCustomLink(db.components().insertPrivateProject().getProjectDto()); + ProjectLinkDto link1 = db.projectLinks().insertCustomLink(projectDto); + ProjectLinkDto link2 = db.projectLinks().insertProvidedLink(projectDto); + db.projectLinks().insertCustomLink(db.components().insertPrivateProject().getProjectDto()); underTest.execute(new TestComputationStepContext()); @@ -103,10 +89,10 @@ public class ExportLinksStepIT { @Test public void throws_ISE_if_error() { - db.componentLinks().insertCustomLink(project); - db.componentLinks().insertProvidedLink(project); - db.componentLinks().insertProvidedLink(project); - db.componentLinks().insertCustomLink(db.components().insertPrivateProject().getProjectDto()); + db.projectLinks().insertCustomLink(projectDto); + db.projectLinks().insertProvidedLink(projectDto); + db.projectLinks().insertProvidedLink(projectDto); + db.projectLinks().insertCustomLink(db.components().insertPrivateProject().getProjectDto()); dumpWriter.failIfMoreThan(2, DumpElement.LINKS); @@ -117,7 +103,7 @@ public class ExportLinksStepIT { @Test public void test_all_fields() { - ProjectLinkDto link = db.componentLinks().insertCustomLink(project, l -> l.setName("name").setHref("href").setType("type")); + ProjectLinkDto link = db.projectLinks().insertCustomLink(projectDto, l -> l.setName("name").setHref("href").setType("type")); underTest.execute(new TestComputationStepContext()); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistProjectLinksStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistProjectLinksStep.java index 9b9d055f0f1..a0f9c71c3cb 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistProjectLinksStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistProjectLinksStep.java @@ -67,20 +67,20 @@ public class PersistProjectLinksStep implements ComputationStep { } try (DbSession session = dbClient.openSession(false)) { - Component project = treeRootHolder.getRoot(); - ScannerReport.Component batchComponent = reportReader.readComponent(project.getReportAttributes().getRef()); - List previousLinks = dbClient.projectLinkDao().selectByProjectUuid(session, project.getUuid()); - mergeLinks(session, project.getUuid(), batchComponent.getLinkList(), previousLinks); + Component rootComponent = treeRootHolder.getRoot(); + ScannerReport.Component batchComponent = reportReader.readComponent(rootComponent.getReportAttributes().getRef()); + List previousLinks = dbClient.projectLinkDao().selectByProjectUuid(session, analysisMetadataHolder.getProject().getUuid()); + mergeLinks(session, analysisMetadataHolder.getProject().getUuid(), batchComponent.getLinkList(), previousLinks); session.commit(); } } - private void mergeLinks(DbSession session, String componentUuid, List links, List previousLinks) { + private void mergeLinks(DbSession session, String projectUuid, List links, List previousLinks) { Set linkType = new HashSet<>(); links.forEach( link -> { String type = convertType(link.getType()); - checkArgument(!linkType.contains(type), "Link of type '%s' has already been declared on component '%s'", type, componentUuid); + checkArgument(!linkType.contains(type), "Link of type '%s' has already been declared on component '%s'", type, projectUuid); linkType.add(type); Optional previousLink = previousLinks.stream() @@ -93,7 +93,7 @@ public class PersistProjectLinksStep implements ComputationStep { dbClient.projectLinkDao().insert(session, new ProjectLinkDto() .setUuid(uuidFactory.create()) - .setProjectUuid(componentUuid) + .setProjectUuid(projectUuid) .setType(type) .setHref(link.getHref())); } diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/component/ProjectLinkDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/component/ProjectLinkDaoIT.java index 466a8cc7060..f438c73ca38 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/component/ProjectLinkDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/component/ProjectLinkDaoIT.java @@ -25,6 +25,7 @@ import org.junit.Test; import org.sonar.api.impl.utils.TestSystem2; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; +import org.sonar.db.project.ProjectDto; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; @@ -38,14 +39,14 @@ public class ProjectLinkDaoIT { private System2 system2 = new TestSystem2().setNow(NOW); @Rule - public DbTester db = DbTester.create(system2); + public DbTester db = DbTester.create(system2, true); private ProjectLinkDao underTest = db.getDbClient().projectLinkDao(); @Test public void select_by_id() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertProvidedLink(project, c -> c + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertProvidedLink(project, c -> c .setUuid("ABCD") .setName("Home") .setType("homepage") @@ -54,7 +55,7 @@ public class ProjectLinkDaoIT { ProjectLinkDto reloaded = underTest.selectByUuid(db.getSession(), link.getUuid()); assertThat(reloaded.getUuid()).isEqualTo("ABCD"); - assertThat(reloaded.getProjectUuid()).isEqualTo(project.uuid()); + assertThat(reloaded.getProjectUuid()).isEqualTo(project.getUuid()); assertThat(reloaded.getType()).isEqualTo("homepage"); assertThat(reloaded.getName()).isEqualTo("Home"); assertThat(reloaded.getHref()).isEqualTo("http://www.struts.org"); @@ -64,17 +65,17 @@ public class ProjectLinkDaoIT { @Test public void select_by_project_uuid() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link1 = db.componentLinks().insertProvidedLink(project); - ProjectLinkDto link2 = db.componentLinks().insertProvidedLink(project); - ProjectLinkDto link3 = db.componentLinks().insertProvidedLink(project); - ComponentDto otherProject = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto otherLink = db.componentLinks().insertProvidedLink(otherProject); - - assertThat(underTest.selectByProjectUuid(db.getSession(), project.uuid())) + ProjectDto project1 = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link1 = db.projectLinks().insertProvidedLink(project1); + ProjectLinkDto link2 = db.projectLinks().insertProvidedLink(project1); + ProjectLinkDto link3 = db.projectLinks().insertProvidedLink(project1); + ProjectDto project2 = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto otherLink = db.projectLinks().insertProvidedLink(project2); + + assertThat(underTest.selectByProjectUuid(db.getSession(), project1.getUuid())) .extracting(ProjectLinkDto::getUuid) .containsExactlyInAnyOrder(link1.getUuid(), link2.getUuid(), link3.getUuid()); - assertThat(underTest.selectByProjectUuid(db.getSession(), otherProject.uuid())) + assertThat(underTest.selectByProjectUuid(db.getSession(), project2.getUuid())) .extracting(ProjectLinkDto::getUuid) .containsExactlyInAnyOrder(otherLink.getUuid()); assertThat(underTest.selectByProjectUuid(db.getSession(), "UNKNOWN")).isEmpty(); @@ -82,16 +83,16 @@ public class ProjectLinkDaoIT { @Test public void select_by_project_uuids() { - ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link1 = db.componentLinks().insertProvidedLink(project1); - ProjectLinkDto link2 = db.componentLinks().insertProvidedLink(project1); - ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link3 = db.componentLinks().insertProvidedLink(project2); + ProjectDto project1 = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link1 = db.projectLinks().insertProvidedLink(project1); + ProjectLinkDto link2 = db.projectLinks().insertProvidedLink(project1); + ProjectDto project2 = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link3 = db.projectLinks().insertProvidedLink(project2); - assertThat(underTest.selectByProjectUuids(db.getSession(), asList(project1.uuid(), project2.uuid()))) + assertThat(underTest.selectByProjectUuids(db.getSession(), asList(project1.getUuid(), project2.getUuid()))) .extracting(ProjectLinkDto::getUuid) .containsOnly(link1.getUuid(), link2.getUuid(), link3.getUuid()); - assertThat(underTest.selectByProjectUuids(db.getSession(), singletonList(project1.uuid()))) + assertThat(underTest.selectByProjectUuids(db.getSession(), singletonList(project1.getUuid()))) .extracting(ProjectLinkDto::getUuid) .containsOnly(link1.getUuid(), link2.getUuid()); assertThat(underTest.selectByProjectUuids(db.getSession(), Collections.emptyList())).isEmpty(); @@ -99,10 +100,10 @@ public class ProjectLinkDaoIT { @Test public void insert() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); ProjectLinkDto link = ProjectLinkTesting.newProvidedLinkDto() .setUuid("ABCD") - .setProjectUuid(project.uuid()) + .setProjectUuid(project.getUuid()) .setName("Home") .setType("homepage") .setHref("http://www.struts.org") @@ -115,7 +116,7 @@ public class ProjectLinkDaoIT { ProjectLinkDto reloaded = underTest.selectByUuid(db.getSession(), link.getUuid()); assertThat(reloaded.getUuid()).isEqualTo("ABCD"); - assertThat(reloaded.getProjectUuid()).isEqualTo(project.uuid()); + assertThat(reloaded.getProjectUuid()).isEqualTo(project.getUuid()); assertThat(reloaded.getType()).isEqualTo("homepage"); assertThat(reloaded.getName()).isEqualTo("Home"); assertThat(reloaded.getHref()).isEqualTo("http://www.struts.org"); @@ -125,8 +126,8 @@ public class ProjectLinkDaoIT { @Test public void update() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertProvidedLink(project, c -> c + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertProvidedLink(project, c -> c .setUuid("ABCD") .setType("ci") .setName("Gihub") @@ -154,8 +155,8 @@ public class ProjectLinkDaoIT { @Test public void delete() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertProvidedLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertProvidedLink(project); underTest.delete(db.getSession(), link.getUuid()); db.getSession().commit(); diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java index 31bbc77973f..1957e7e368a 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/project/ProjectDaoIT.java @@ -39,6 +39,7 @@ import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; import org.sonar.api.resources.Qualifiers; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; +import org.sonar.db.Pagination; import org.sonar.db.audit.AuditPersister; import org.sonar.db.audit.NoOpAuditPersister; import org.sonar.db.component.BranchDto; @@ -51,6 +52,7 @@ import org.sonar.db.qualityprofile.QProfileDto; import static java.util.Collections.emptySet; import static org.apache.commons.lang.math.RandomUtils.nextInt; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.in; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -344,6 +346,30 @@ public class ProjectDaoIT { assertThat(projectUuids).containsExactlyInAnyOrder(project.projectUuid(), project2.projectUuid()); } + // methodName_when_should + @Test + public void selectByUuids_whenUuidsAreEmptyWithPagination_shouldReturnEmptyList() { + db.components().insertPublicProject(); + + List projectDtos = projectDao.selectByUuids(db.getSession(), emptySet(), Pagination.forPage(1).andSize(1)); + + assertThat(projectDtos).isEmpty(); + } + + @Test + public void selectByUuids_whenPagination_shouldReturnSubSetOfPagination() { + Set projectUuids = new HashSet<>(); + for (int i = 0; i < 5; i++) { + final String name = "Project_" + i; + String projectUuid = db.components().insertPublicProject(c -> c.setName(name)).projectUuid(); + projectUuids.add(projectUuid); + } + + List projectDtos = projectDao.selectByUuids(db.getSession(), projectUuids, Pagination.forPage(2).andSize(2)); + + assertThat(projectDtos).extracting(ProjectDto::getName).containsOnly("Project_2", "Project_3"); + } + private void insertDefaultQualityProfile(String language) { QProfileDto profile = db.qualityProfiles().insert(qp -> qp.setIsBuiltIn(true).setLanguage(language)); db.qualityProfiles().setAsDefault(profile); diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java index fda4a64bcb8..94684662079 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/user/RoleDaoIT.java @@ -20,10 +20,12 @@ package org.sonar.db.user; import java.util.List; +import java.util.Set; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.sonar.api.resources.Qualifiers; import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; import org.sonar.core.util.Uuids; @@ -37,6 +39,8 @@ import static org.sonar.db.permission.GlobalPermission.ADMINISTER; public class RoleDaoIT { + private static final Set PROJECT_QUALIFIER = Set.of(Qualifiers.PROJECT); + @Rule public DbTester db = DbTester.create(System2.INSTANCE); @@ -58,18 +62,18 @@ public class RoleDaoIT { @Test public void selectComponentUuidsByPermissionAndUserId_throws_IAR_if_permission_USER_is_specified() { - expectUnsupportedUserAndCodeViewerPermission(() -> underTest.selectEntityUuidsByPermissionAndUserUuid(dbSession, UserRole.USER, Uuids.createFast())); + expectUnsupportedUserAndCodeViewerPermission(() -> underTest.selectEntityUuidsByPermissionAndUserUuidAndQualifier(dbSession, UserRole.USER, Uuids.createFast(), PROJECT_QUALIFIER)); } @Test public void selectComponentUuidsByPermissionAndUserId_throws_IAR_if_permission_CODEVIEWER_is_specified() { - expectUnsupportedUserAndCodeViewerPermission(() -> underTest.selectEntityUuidsByPermissionAndUserUuid(dbSession, UserRole.CODEVIEWER, Uuids.createFast())); + expectUnsupportedUserAndCodeViewerPermission(() -> underTest.selectEntityUuidsByPermissionAndUserUuidAndQualifier(dbSession, UserRole.CODEVIEWER, Uuids.createFast(), PROJECT_QUALIFIER)); } private void expectUnsupportedUserAndCodeViewerPermission(ThrowingCallable callback) { assertThatThrownBy(callback) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Permissions [user, codeviewer] are not supported by selectEntityUuidsByPermissionAndUserUuid"); + .hasMessage("Permissions [user, codeviewer] are not supported by selectEntityUuidsByPermissionAndUserUuidAndQualifier"); } @Test @@ -83,7 +87,7 @@ public class RoleDaoIT { // project permission on another permission - not returned db.users().insertProjectPermissionOnUser(user1, UserRole.ISSUE_ADMIN, project1); - List entityUuids = underTest.selectEntityUuidsByPermissionAndUserUuid(dbSession, UserRole.ADMIN, user1.getUuid()); + List entityUuids = underTest.selectEntityUuidsByPermissionAndUserUuidAndQualifier(dbSession, UserRole.ADMIN, user1.getUuid(), PROJECT_QUALIFIER); assertThat(entityUuids).containsExactly(project1.uuid(), project2.uuid()); } @@ -104,7 +108,7 @@ public class RoleDaoIT { // project permission on another permission - not returned db.users().insertProjectPermissionOnGroup(group1, UserRole.ISSUE_ADMIN, project1); - List result = underTest.selectEntityUuidsByPermissionAndUserUuid(dbSession, UserRole.ADMIN, user1.getUuid()); + List result = underTest.selectEntityUuidsByPermissionAndUserUuidAndQualifier(dbSession, UserRole.ADMIN, user1.getUuid(), PROJECT_QUALIFIER); assertThat(result).containsExactly(project1.uuid(), project2.uuid()); } @@ -135,4 +139,6 @@ public class RoleDaoIT { assertThat(db.getDbClient().groupPermissionDao().selectGlobalPermissionsOfGroup(db.getSession(), null)).containsOnly("scan", "provisioning"); } + + // TODO : add test for qualifier method. } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java index 44ef0ff0e8b..47471258409 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDao.java @@ -26,6 +26,7 @@ import javax.annotation.Nullable; import org.sonar.api.utils.System2; import org.sonar.db.Dao; import org.sonar.db.DbSession; +import org.sonar.db.Pagination; import org.sonar.db.audit.AuditPersister; import org.sonar.db.audit.model.ComponentNewValue; @@ -106,6 +107,13 @@ public class ProjectDao implements Dao { return executeLargeInputs(uuids, partition -> mapper(session).selectByUuids(partition)); } + public List selectByUuids(DbSession session, Set uuids, Pagination pagination) { + if (uuids.isEmpty()) { + return emptyList(); + } + return mapper(session).selectByUuidsWithPagination(uuids, pagination); + } + public void updateVisibility(DbSession session, String uuid, boolean isPrivate) { mapper(session).updateVisibility(uuid, isPrivate, system2.now()); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java index d778d860e42..e189566d7bd 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectMapper.java @@ -25,6 +25,7 @@ import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.ibatis.annotations.Param; +import org.sonar.db.Pagination; public interface ProjectMapper { @@ -46,6 +47,8 @@ public interface ProjectMapper { List selectByUuids(@Param("uuids") Collection uuids); + List selectByUuidsWithPagination(@Param("uuids") Collection uuids, @Param("pagination") Pagination pagination); + List selectAll(); void updateTags(ProjectDto project); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/RoleDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/RoleDao.java index afea4198291..b5feddc4800 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/RoleDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/RoleDao.java @@ -20,6 +20,7 @@ package org.sonar.db.user; import com.google.common.collect.ImmutableSet; +import java.util.Collection; import java.util.List; import java.util.Set; import org.sonar.api.web.UserRole; @@ -40,11 +41,11 @@ public class RoleDao implements Dao { * @throws IllegalArgumentException this method does not support permissions {@link UserRole#USER user} nor * {@link UserRole#CODEVIEWER codeviewer} because it does not support public root components. */ - public List selectEntityUuidsByPermissionAndUserUuid(DbSession dbSession, String permission, String userUuid) { + public List selectEntityUuidsByPermissionAndUserUuidAndQualifier(DbSession dbSession, String permission, String userUuid, Collection qualifiers) { checkArgument( !UNSUPPORTED_PROJECT_PERMISSIONS.contains(permission), - "Permissions %s are not supported by selectEntityUuidsByPermissionAndUserUuid", UNSUPPORTED_PROJECT_PERMISSIONS); - return mapper(dbSession).selectEntityUuidsByPermissionAndUserUuid(permission, userUuid); + "Permissions %s are not supported by selectEntityUuidsByPermissionAndUserUuidAndQualifier", UNSUPPORTED_PROJECT_PERMISSIONS); + return mapper(dbSession).selectEntityUuidsByPermissionAndUserUuidAndQualifier(permission, userUuid, qualifiers); } public void deleteGroupRolesByGroupUuid(DbSession session, String groupUuid) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/RoleMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/RoleMapper.java index 722a79bd40c..ccbb3b8b6e9 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/RoleMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/RoleMapper.java @@ -19,12 +19,14 @@ */ package org.sonar.db.user; +import java.util.Collection; import java.util.List; import org.apache.ibatis.annotations.Param; public interface RoleMapper { - List selectEntityUuidsByPermissionAndUserUuid(@Param("permission") String permission, @Param("userUuid") String userUuid); + List selectEntityUuidsByPermissionAndUserUuidAndQualifier(@Param("permission") String permission, + @Param("userUuid") String userUuid, @Param("qualifiers") Collection qualifiers); void deleteGroupRolesByGroupUuid(String groupUuid); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml index f8a5d2ea185..362f33aa3c6 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/project/ProjectMapper.xml @@ -40,6 +40,19 @@ + + - select - ur.entity_uuid - from - user_roles ur - where - ur.user_uuid = #{userUuid,jdbcType=VARCHAR} - and ur.role = #{permission,jdbcType=VARCHAR} - and ur.entity_uuid is not null - union - select - gr.entity_uuid - from - group_roles gr - inner join groups_users gu on - gr.group_uuid=gu.group_uuid - where - gr.role = #{permission,jdbcType=VARCHAR} - and gr.entity_uuid is not null - and gu.user_uuid=#{userUuid,jdbcType=VARCHAR} - order by - entity_uuid + diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java index 0ffa3565469..6a29d3cdd3f 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/DbTester.java @@ -69,7 +69,7 @@ public class DbTester extends AbstractDbTester { private DbSession session = null; private final UserDbTester userTester; private final ComponentDbTester componentTester; - private final ProjectLinkDbTester componentLinkTester; + private final ProjectLinkDbTester projectLinkTester; private final FavoriteDbTester favoriteTester; private final EventDbTester eventTester; private final PermissionTemplateDbTester permissionTemplateTester; @@ -98,7 +98,7 @@ public class DbTester extends AbstractDbTester { initDbClient(); this.userTester = new UserDbTester(this); this.componentTester = new ComponentDbTester(this, useDifferentProjectUuids); - this.componentLinkTester = new ProjectLinkDbTester(this); + this.projectLinkTester = new ProjectLinkDbTester(this); this.favoriteTester = new FavoriteDbTester(this); this.eventTester = new EventDbTester(this); this.permissionTemplateTester = new PermissionTemplateDbTester(this); @@ -193,8 +193,8 @@ public class DbTester extends AbstractDbTester { return componentTester; } - public ProjectLinkDbTester componentLinks() { - return componentLinkTester; + public ProjectLinkDbTester projectLinks() { + return projectLinkTester; } public FavoriteDbTester favorites() { diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ProjectLinkDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ProjectLinkDbTester.java index 1e1542aeb8e..46114943590 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ProjectLinkDbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ProjectLinkDbTester.java @@ -39,25 +39,7 @@ public class ProjectLinkDbTester { this.dbClient = db.getDbClient(); this.dbSession = db.getSession(); } - - @SafeVarargs - public final ProjectLinkDto insertProvidedLink(ComponentDto project, Consumer... dtoPopulators) { - return insertLink(project, newProvidedLinkDto(), dtoPopulators); - } - - @SafeVarargs - public final ProjectLinkDto insertCustomLink(ComponentDto project, Consumer... dtoPopulators) { - return insertLink(project, newCustomLinkDto(), dtoPopulators); - } - - @SafeVarargs - private final ProjectLinkDto insertLink(ComponentDto project, ProjectLinkDto componentLink, Consumer... dtoPopulators) { - Arrays.stream(dtoPopulators).forEach(dtoPopulator -> dtoPopulator.accept(componentLink)); - dbClient.projectLinkDao().insert(dbSession, componentLink.setProjectUuid(project.uuid())); - db.commit(); - return componentLink; - } - + @SafeVarargs public final ProjectLinkDto insertProvidedLink(ProjectDto project, Consumer... dtoPopulators) { return insertLink(project, newProvidedLinkDto(), dtoPopulators); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/SearchMyProjectsActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/SearchMyProjectsActionIT.java index 5c0e9f88684..2abe6aae204 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/SearchMyProjectsActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/SearchMyProjectsActionIT.java @@ -33,10 +33,13 @@ import org.sonar.core.util.Uuids; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; +import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ProjectData; import org.sonar.db.component.ProjectLinkDto; import org.sonar.db.component.SnapshotDto; import org.sonar.db.metric.MetricDto; +import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; import org.sonar.server.exceptions.UnauthorizedException; @@ -48,7 +51,6 @@ import org.sonarqube.ws.Projects.SearchMyProjectsWsResponse.Project; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; import static org.sonar.db.component.SnapshotTesting.newAnalysis; import static org.sonar.db.measure.MeasureTesting.newLiveMeasure; import static org.sonar.db.metric.MetricTesting.newMetricDto; @@ -60,7 +62,7 @@ public class SearchMyProjectsActionIT { @Rule public final UserSessionRule userSession = UserSessionRule.standalone(); @Rule - public final DbTester db = DbTester.create(System2.INSTANCE); + public final DbTester db = DbTester.create(System2.INSTANCE, true); private final DbClient dbClient = db.getDbClient(); private final DbSession dbSession = db.getSession(); @@ -80,18 +82,18 @@ public class SearchMyProjectsActionIT { @Test public void search_json_example() { - ComponentDto jdk7 = insertJdk7(); - ComponentDto cLang = insertClang(); - db.componentLinks().insertProvidedLink(jdk7, l -> l.setHref("http://www.oracle.com").setType(ProjectLinkDto.TYPE_HOME_PAGE).setName("Home")); - db.componentLinks().insertProvidedLink(jdk7, l -> l.setHref("http://download.java.net/openjdk/jdk8/").setType(ProjectLinkDto.TYPE_SOURCES).setName("Sources")); + ProjectData jdk7 = insertJdk7(); + ProjectData cLang = insertClang(); + db.projectLinks().insertProvidedLink(jdk7.getProjectDto(), l -> l.setHref("http://www.oracle.com").setType(ProjectLinkDto.TYPE_HOME_PAGE).setName("Home")); + db.projectLinks().insertProvidedLink(jdk7.getProjectDto(), l -> l.setHref("http://download.java.net/openjdk/jdk8/").setType(ProjectLinkDto.TYPE_SOURCES).setName("Sources")); long oneTime = DateUtils.parseDateTime("2016-06-10T13:17:53+0000").getTime(); long anotherTime = DateUtils.parseDateTime("2016-06-11T14:25:53+0000").getTime(); - SnapshotDto jdk7Snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(jdk7).setCreatedAt(oneTime)); - SnapshotDto cLangSnapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(cLang).setCreatedAt(anotherTime)); - dbClient.liveMeasureDao().insert(dbSession, newLiveMeasure(jdk7, alertStatusMetric).setData(Level.ERROR.name())); - dbClient.liveMeasureDao().insert(dbSession, newLiveMeasure(cLang, alertStatusMetric).setData(Level.OK.name())); - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7); - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, cLang); + SnapshotDto jdk7Snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(jdk7.getMainBranchDto()).setCreatedAt(oneTime)); + SnapshotDto cLangSnapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(cLang.getMainBranchDto()).setCreatedAt(anotherTime)); + dbClient.liveMeasureDao().insert(dbSession, newLiveMeasure(jdk7.getMainBranchDto(), alertStatusMetric).setData(Level.ERROR.name())); + dbClient.liveMeasureDao().insert(dbSession, newLiveMeasure(cLang.getMainBranchDto(), alertStatusMetric).setData(Level.OK.name())); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7.getProjectDto()); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, cLang.getProjectDto()); db.commit(); System.setProperty("user.timezone", "UTC"); @@ -102,11 +104,11 @@ public class SearchMyProjectsActionIT { @Test public void return_only_current_user_projects() { - ComponentDto jdk7 = insertJdk7(); - ComponentDto cLang = insertClang(); + ProjectData jdk7 = insertJdk7(); + ProjectData cLang = insertClang(); UserDto anotherUser = db.users().insertUser(newUserDto()); - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7); - db.users().insertProjectPermissionOnUser(anotherUser, UserRole.ADMIN, cLang); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7.getProjectDto()); + db.users().insertProjectPermissionOnUser(anotherUser, UserRole.ADMIN, cLang.getProjectDto()); SearchMyProjectsWsResponse result = callWs(); @@ -144,8 +146,8 @@ public class SearchMyProjectsActionIT { public void paginate_projects() { for (int i = 0; i < 10; i++) { int j = i; - ComponentDto project = db.components().insertPrivateProject(p -> p.setName("project-" + j)).getMainBranchComponent(); - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, project); + ProjectData project = db.components().insertPrivateProject(p -> p.setName("project-" + j)); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, project.getProjectDto()); } SearchMyProjectsWsResponse result = ws.newRequest() @@ -153,17 +155,17 @@ public class SearchMyProjectsActionIT { .setParam(Param.PAGE_SIZE, "3") .executeProtobuf(SearchMyProjectsWsResponse.class); - assertThat(result.getProjectsCount()).isEqualTo(3); assertThat(result.getProjectsList()).extracting(Project::getName).containsExactly("project-3", "project-4", "project-5"); + assertThat(result.getProjectsCount()).isEqualTo(3); } @Test public void return_only_projects_when_user_is_admin() { - ComponentDto jdk7 = insertJdk7(); - ComponentDto clang = insertClang(); + ProjectData jdk7 = insertJdk7(); + ProjectData clang = insertClang(); - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7); - db.users().insertProjectPermissionOnUser(user, UserRole.ISSUE_ADMIN, clang); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7.getProjectDto()); + db.users().insertProjectPermissionOnUser(user, UserRole.ISSUE_ADMIN, clang.getProjectDto()); SearchMyProjectsWsResponse result = callWs(); @@ -172,10 +174,10 @@ public class SearchMyProjectsActionIT { @Test public void does_not_return_views() { - ComponentDto jdk7 = insertJdk7(); - ComponentDto portfolio = insertPortfolio(); + ProjectData jdk7 = insertJdk7(); + PortfolioDto portfolio = insertPortfolio(); - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7.getProjectDto()); db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, portfolio); SearchMyProjectsWsResponse result = callWs(); @@ -185,27 +187,27 @@ public class SearchMyProjectsActionIT { @Test public void does_not_return_branches() { - ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); - ComponentDto branch = db.components().insertProjectBranch(project); - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, project); + ProjectData project = db.components().insertPublicProject(); + BranchDto branch = db.components().insertProjectBranch(project.getProjectDto()); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, project.getProjectDto()); SearchMyProjectsWsResponse result = callWs(); assertThat(result.getProjectsList()) .extracting(Project::getKey) - .containsExactlyInAnyOrder(project.getKey()); + .containsExactlyInAnyOrder(project.getProjectDto().getKey()); } @Test public void admin_via_groups() { - ComponentDto jdk7 = insertJdk7(); - ComponentDto cLang = insertClang(); + ProjectData jdk7 = insertJdk7(); + ProjectData cLang = insertClang(); GroupDto group = db.users().insertGroup(); db.users().insertMember(group, user); - db.users().insertProjectPermissionOnGroup(group, UserRole.ADMIN, jdk7); - db.users().insertProjectPermissionOnGroup(group, UserRole.USER, cLang); + db.users().insertEntityPermissionOnGroup(group, UserRole.ADMIN, jdk7.getProjectDto()); + db.users().insertEntityPermissionOnGroup(group, UserRole.USER, cLang.getProjectDto()); SearchMyProjectsWsResponse result = callWs(); @@ -214,18 +216,18 @@ public class SearchMyProjectsActionIT { @Test public void admin_via_groups_and_users() { - ComponentDto jdk7 = insertJdk7(); - ComponentDto cLang = insertClang(); - ComponentDto sonarqube = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectData jdk7 = insertJdk7(); + ProjectData cLang = insertClang(); + ProjectData sonarqube = db.components().insertPrivateProject(); GroupDto group = db.users().insertGroup(); db.users().insertMember(group, user); - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7); - db.users().insertProjectPermissionOnGroup(group, UserRole.ADMIN, cLang); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, jdk7.getProjectDto()); + db.users().insertEntityPermissionOnGroup(group, UserRole.ADMIN, cLang.getProjectDto()); // admin via group and user - db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, sonarqube); - db.users().insertProjectPermissionOnGroup(group, UserRole.ADMIN, sonarqube); + db.users().insertProjectPermissionOnUser(user, UserRole.ADMIN, sonarqube.getProjectDto()); + db.users().insertEntityPermissionOnGroup(group, UserRole.ADMIN, sonarqube.getProjectDto()); SearchMyProjectsWsResponse result = callWs(); @@ -246,22 +248,22 @@ public class SearchMyProjectsActionIT { .isInstanceOf(UnauthorizedException.class); } - private ComponentDto insertClang() { + private ProjectData insertClang() { return db.components().insertPrivateProject(Uuids.UUID_EXAMPLE_01, p -> p .setName("Clang") - .setKey("clang")).getMainBranchComponent(); + .setKey("clang")); } - private ComponentDto insertJdk7() { + private ProjectData insertJdk7() { return db.components().insertPrivateProject(Uuids.UUID_EXAMPLE_02, p -> p .setName("JDK 7") .setKey("net.java.openjdk:jdk7") - .setDescription("JDK")).getMainBranchComponent(); + .setDescription("JDK")); } - private ComponentDto insertPortfolio() { + private PortfolioDto insertPortfolio() { String uuid = "752d8bfd-420c-4a83-a4e5-8ab19b13c8fc"; - return db.components().insertPublicPortfolio(p -> p.setUuid("752d8bfd-420c-4a83-a4e5-8ab19b13c8fc") + return db.components().insertPublicPortfolioDto(p -> p.setUuid("752d8bfd-420c-4a83-a4e5-8ab19b13c8fc") .setName("Java") .setKey("Java"), p -> p.setRootUuid(uuid)); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projectlink/ws/DeleteActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projectlink/ws/DeleteActionIT.java index 3c1fbfb4091..0f3637ac023 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projectlink/ws/DeleteActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projectlink/ws/DeleteActionIT.java @@ -26,8 +26,8 @@ import org.sonar.api.utils.System2; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ProjectLinkDto; +import org.sonar.db.project.ProjectDto; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -45,7 +45,7 @@ public class DeleteActionIT { @Rule public UserSessionRule userSession = UserSessionRule.standalone(); @Rule - public DbTester db = DbTester.create(System2.INSTANCE); + public DbTester db = DbTester.create(System2.INSTANCE, true); private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); @@ -54,8 +54,8 @@ public class DeleteActionIT { @Test public void no_response() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertCustomLink(project); logInAsProjectAdministrator(project); TestResponse response = deleteLink(link); @@ -66,8 +66,8 @@ public class DeleteActionIT { @Test public void remove_custom_link() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertCustomLink(project); logInAsProjectAdministrator(project); deleteLink(link); @@ -77,10 +77,10 @@ public class DeleteActionIT { @Test public void keep_links_of_another_project() { - ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto customLink1 = db.componentLinks().insertCustomLink(project1); - ProjectLinkDto customLink2 = db.componentLinks().insertCustomLink(project2); + ProjectDto project1 = db.components().insertPrivateProject().getProjectDto(); + ProjectDto project2 = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto customLink1 = db.projectLinks().insertCustomLink(project1); + ProjectLinkDto customLink2 = db.projectLinks().insertCustomLink(project2); userSession.logIn().addProjectPermission(ADMIN, project1, project2); deleteLink(customLink1); @@ -91,8 +91,8 @@ public class DeleteActionIT { @Test public void fail_when_delete_provided_link() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertProvidedLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertProvidedLink(project); logInAsProjectAdministrator(project); assertThatThrownBy(() -> deleteLink(link)) @@ -106,13 +106,13 @@ public class DeleteActionIT { .setMethod("POST") .setParam(PARAM_ID, "UNKNOWN") .execute()) - .isInstanceOf(NotFoundException.class); + .isInstanceOf(NotFoundException.class); } @Test public void fail_if_anonymous() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertCustomLink(project); userSession.anonymous(); assertThatThrownBy(() -> deleteLink(link)) @@ -121,8 +121,8 @@ public class DeleteActionIT { @Test public void fail_if_not_project_admin() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertCustomLink(project); userSession.logIn(); assertThatThrownBy(() -> deleteLink(link)) @@ -154,7 +154,7 @@ public class DeleteActionIT { assertThat(dbClient.projectLinkDao().selectByUuid(dbSession, uuid)).isNotNull(); } - private void logInAsProjectAdministrator(ComponentDto project) { + private void logInAsProjectAdministrator(ProjectDto project) { userSession.logIn().addProjectPermission(ADMIN, project); } } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projectlink/ws/SearchActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projectlink/ws/SearchActionIT.java index 73a10a7f898..3a6a3971a7f 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projectlink/ws/SearchActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/projectlink/ws/SearchActionIT.java @@ -28,6 +28,7 @@ import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.ProjectLinkDto; +import org.sonar.db.project.ProjectDto; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; @@ -51,7 +52,7 @@ public class SearchActionIT { @Rule public UserSessionRule userSession = UserSessionRule.standalone(); @Rule - public DbTester db = DbTester.create(System2.INSTANCE); + public DbTester db = DbTester.create(System2.INSTANCE, true); private DbClient dbClient = db.getDbClient(); @@ -59,9 +60,9 @@ public class SearchActionIT { @Test public void example() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - db.componentLinks().insertProvidedLink(project, l -> l.setUuid("1").setType("homepage").setName("Homepage").setHref("http://example.org")); - db.componentLinks().insertCustomLink(project, l -> l.setUuid("2").setType("custom").setName("Custom").setHref("http://example.org/custom")); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + db.projectLinks().insertProvidedLink(project, l -> l.setUuid("1").setType("homepage").setName("Homepage").setHref("http://example.org")); + db.projectLinks().insertCustomLink(project, l -> l.setUuid("2").setType("custom").setName("Custom").setHref("http://example.org/custom")); logInAsProjectAdministrator(project); String result = ws.newRequest() @@ -73,11 +74,11 @@ public class SearchActionIT { @Test public void request_by_project_id() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertCustomLink(project); logInAsProjectAdministrator(project); - SearchWsResponse response = callByUuid(project.uuid()); + SearchWsResponse response = callByUuid(project.getUuid()); assertThat(response.getLinksList()) .extracting(Link::getId, Link::getName) @@ -86,8 +87,8 @@ public class SearchActionIT { @Test public void request_by_project_key() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertCustomLink(project); logInAsProjectAdministrator(project); SearchWsResponse response = callByKey(project.getKey()); @@ -99,9 +100,9 @@ public class SearchActionIT { @Test public void response_fields() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto homepageLink = db.componentLinks().insertProvidedLink(project); - ProjectLinkDto customLink = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto homepageLink = db.projectLinks().insertProvidedLink(project); + ProjectLinkDto customLink = db.projectLinks().insertCustomLink(project); logInAsProjectAdministrator(project); SearchWsResponse response = callByKey(project.getKey()); @@ -114,10 +115,10 @@ public class SearchActionIT { @Test public void several_projects() { - ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link1 = db.componentLinks().insertCustomLink(project1); - ProjectLinkDto link2 = db.componentLinks().insertCustomLink(project2); + ProjectDto project1 = db.components().insertPrivateProject().getProjectDto(); + ProjectDto project2 = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link1 = db.projectLinks().insertCustomLink(project1); + ProjectLinkDto link2 = db.projectLinks().insertCustomLink(project2); userSession.addProjectPermission(USER, project1); userSession.addProjectPermission(USER, project2); @@ -130,8 +131,8 @@ public class SearchActionIT { @Test public void request_does_not_fail_when_link_has_no_name() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertProvidedLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertProvidedLink(project); logInAsProjectAdministrator(project); SearchWsResponse response = callByKey(project.getKey()); @@ -143,8 +144,8 @@ public class SearchActionIT { @Test public void project_administrator_can_search_for_links() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertCustomLink(project); logInAsProjectAdministrator(project); SearchWsResponse response = callByKey(project.getKey()); @@ -156,8 +157,8 @@ public class SearchActionIT { @Test public void project_user_can_search_for_links() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); - ProjectLinkDto link = db.componentLinks().insertCustomLink(project); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectLinkDto link = db.projectLinks().insertCustomLink(project); userSession.logIn().addProjectPermission(USER, project); SearchWsResponse response = callByKey(project.getKey()); @@ -207,12 +208,12 @@ public class SearchActionIT { @Test public void fail_when_both_id_and_key_are_provided() { - ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent(); + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); logInAsProjectAdministrator(project); assertThatThrownBy(() -> ws.newRequest() .setParam(PARAM_PROJECT_KEY, project.getKey()) - .setParam(PARAM_PROJECT_ID, project.uuid()) + .setParam(PARAM_PROJECT_ID, project.getUuid()) .execute()) .isInstanceOf(IllegalArgumentException.class); } @@ -263,7 +264,7 @@ public class SearchActionIT { .executeProtobuf(SearchWsResponse.class); } - private void logInAsProjectAdministrator(ComponentDto project) { + private void logInAsProjectAdministrator(ProjectDto project) { userSession.logIn().addProjectPermission(ADMIN, project); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java index 5aa2b9bd038..520e24a9228 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchMyProjectsAction.java @@ -20,9 +20,10 @@ package org.sonar.server.project.ws; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; import java.util.List; +import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.api.measures.CoreMetrics; @@ -35,11 +36,12 @@ import org.sonar.api.web.UserRole; import org.sonar.db.DatabaseUtils; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentQuery; +import org.sonar.db.Pagination; +import org.sonar.db.component.BranchDto; import org.sonar.db.component.ProjectLinkDto; import org.sonar.db.component.SnapshotDto; import org.sonar.db.measure.LiveMeasureDto; +import org.sonar.db.project.ProjectDto; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Projects.SearchMyProjectsWsResponse; import org.sonarqube.ws.Projects.SearchMyProjectsWsResponse.Link; @@ -51,7 +53,6 @@ import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; import static java.util.Optional.ofNullable; import static org.sonar.api.utils.DateUtils.formatDateTime; -import static org.sonar.api.utils.Paging.offset; import static org.sonar.server.project.ws.SearchMyProjectsData.builder; import static org.sonar.server.ws.WsUtils.writeProtobuf; @@ -97,6 +98,7 @@ public class SearchMyProjectsAction implements ProjectsWsAction { SearchMyProjectsWsResponse.Builder response = SearchMyProjectsWsResponse.newBuilder(); ProjectDtoToWs projectDtoToWs = new ProjectDtoToWs(data); + data.projects().stream() .map(projectDtoToWs) .forEach(response::addProjects); @@ -121,7 +123,7 @@ public class SearchMyProjectsAction implements ProjectsWsAction { .build(); } - private static class ProjectDtoToWs implements Function { + private static class ProjectDtoToWs implements Function { private final SearchMyProjectsData data; private ProjectDtoToWs(SearchMyProjectsData data) { @@ -129,21 +131,23 @@ public class SearchMyProjectsAction implements ProjectsWsAction { } @Override - public Project apply(ComponentDto dto) { + public Project apply(ProjectDto dto) { Project.Builder project = Project.newBuilder(); + project .setKey(dto.getKey()) - .setName(dto.name()); - data.lastSnapshot(dto.uuid()).ifPresent(s -> { + .setName(dto.getName()); + ofNullable(emptyToNull(dto.getDescription())).ifPresent(project::setDescription); + data.projectLinksFor(dto.getUuid()).stream() + .map(ProjectLinkDtoToWs.INSTANCE) + .forEach(project::addLinks); + + String mainBranchUuid = data.mainBranchUuidForProjectUuid(dto.getUuid()); + data.lastSnapshot(mainBranchUuid).ifPresent(s -> { project.setLastAnalysisDate(formatDateTime(s.getCreatedAt())); ofNullable(s.getRevision()).ifPresent(project::setRevision); }); - data.qualityGateStatusFor(dto.uuid()).ifPresent(project::setQualityGate); - ofNullable(emptyToNull(dto.description())).ifPresent(project::setDescription); - - data.projectLinksFor(dto.uuid()).stream() - .map(ProjectLinkDtoToWs.INSTANCE) - .forEach(project::addLinks); + data.qualityGateStatusFor(mainBranchUuid).ifPresent(project::setQualityGate); return project.build(); } @@ -171,14 +175,22 @@ public class SearchMyProjectsAction implements ProjectsWsAction { private SearchMyProjectsData load(DbSession dbSession, SearchMyProjectsRequest request) { SearchMyProjectsData.Builder data = builder(); ProjectsResult searchResult = searchProjects(dbSession, request); - List projects = searchResult.projects; - List projectUuids = Lists.transform(projects, ComponentDto::branchUuid); + List projects = searchResult.projects; + + List projectUuids = projects.stream().map(ProjectDto::getUuid).toList(); List projectLinks = dbClient.projectLinkDao().selectByProjectUuids(dbSession, projectUuids); - List snapshots = dbClient.snapshotDao().selectLastAnalysesByRootComponentUuids(dbSession, projectUuids); + + List branches = searchResult.branches; + + Set mainBranchUuids = branches.stream().map(BranchDto::getUuid).collect(Collectors.toSet()); + List snapshots = dbClient.snapshotDao() + .selectLastAnalysesByRootComponentUuids(dbSession, mainBranchUuids); List qualityGates = dbClient.liveMeasureDao() - .selectByComponentUuidsAndMetricKeys(dbSession, projectUuids, singletonList(CoreMetrics.ALERT_STATUS_KEY)); + .selectByComponentUuidsAndMetricKeys(dbSession, mainBranchUuids, singletonList(CoreMetrics.ALERT_STATUS_KEY)); - data.setProjects(projects) + data + .setProjects(projects) + .setBranches(searchResult.branches) .setProjectLinks(projectLinks) .setSnapshots(snapshots) .setQualityGates(qualityGates) @@ -190,25 +202,35 @@ public class SearchMyProjectsAction implements ProjectsWsAction { private ProjectsResult searchProjects(DbSession dbSession, SearchMyProjectsRequest request) { String userUuid = requireNonNull(userSession.getUuid(), "Current user must be authenticated"); - List componentUuids = dbClient.roleDao().selectEntityUuidsByPermissionAndUserUuid(dbSession, UserRole.ADMIN, userUuid); - ComponentQuery dbQuery = ComponentQuery.builder() - .setQualifiers(Qualifiers.PROJECT) - .setComponentUuids(ImmutableSet.copyOf(componentUuids.subList(0, Math.min(componentUuids.size(), DatabaseUtils.PARTITION_SIZE_FOR_ORACLE)))) - .build(); + List entitiesUuid = dbClient.roleDao().selectEntityUuidsByPermissionAndUserUuidAndQualifier(dbSession, UserRole.ADMIN, userUuid, Set.of(Qualifiers.PROJECT)); + + ImmutableSet subSetEntityUuids = ImmutableSet.copyOf(entitiesUuid.subList(0, Math.min(entitiesUuid.size(), DatabaseUtils.PARTITION_SIZE_FOR_ORACLE))); + Pagination pagination = Pagination.forPage(request.page).andSize(request.pageSize); + List projectDtos = dbClient.projectDao().selectByUuids(dbSession, subSetEntityUuids, pagination); + + List branchDtos = dbClient.branchDao().selectMainBranchesByProjectUuids(dbSession, projectDtos.stream().map(ProjectDto::getUuid).collect(Collectors.toSet())); - return new ProjectsResult( - dbClient.componentDao().selectByQuery(dbSession, dbQuery, offset(request.getPage(), request.getPageSize()), request.getPageSize()), - dbClient.componentDao().countByQuery(dbSession, dbQuery)); + return new ProjectsResult(projectDtos, branchDtos, subSetEntityUuids.size()); } private static class ProjectsResult { - private final List projects; + + private final List projects; + private final List branches; private final int total; - private ProjectsResult(List projects, int total) { + private ProjectsResult(List projects, List branches, int total) { this.projects = projects; + this.branches = branches; + assertThatAllCollectionsHaveSameSize(projects, branches); this.total = total; } + + private static void assertThatAllCollectionsHaveSameSize(List projects, List branches) { + if (projects.size() != branches.size()) { + throw new IllegalStateException("There must be the same number of projects as the branches."); + } + } } private static class SearchMyProjectsRequest { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java index 59f077e6c0d..cc24753be4f 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/SearchMyProjectsData.java @@ -26,10 +26,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.BranchDto; import org.sonar.db.component.ProjectLinkDto; import org.sonar.db.component.SnapshotDto; import org.sonar.db.measure.LiveMeasureDto; +import org.sonar.db.project.ProjectDto; import static com.google.common.collect.ImmutableList.copyOf; import static java.util.Objects.requireNonNull; @@ -37,7 +38,9 @@ import static java.util.function.Function.identity; import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; class SearchMyProjectsData { - private final List projects; + + private final List projects; + private final Map branchUuidByProjectUuids; private final ListMultimap projectLinksByProjectUuid; private final Map snapshotsByComponentUuid; private final Map qualityGateStatuses; @@ -45,17 +48,20 @@ class SearchMyProjectsData { private SearchMyProjectsData(Builder builder) { this.projects = copyOf(builder.projects); + this.branchUuidByProjectUuids = buildBranchUuidByProjectUuidMap(builder.branches); this.projectLinksByProjectUuid = buildProjectLinks(builder.projectLinks); this.snapshotsByComponentUuid =builder.snapshots.stream().collect(uniqueIndex(SnapshotDto::getComponentUuid, identity())); this.qualityGateStatuses = buildQualityGateStatuses(builder.qualityGates); this.totalNbOfProject = builder.totalNbOfProjects; } + + static Builder builder() { return new Builder(); } - List projects() { + List projects() { return projects; } @@ -80,14 +86,29 @@ class SearchMyProjectsData { dtos.forEach(projectLink -> projectLinks.put(projectLink.getProjectUuid(), projectLink)); return projectLinks.build(); } + private static Map buildBranchUuidByProjectUuidMap(List branches) { + return branches.stream().collect(Collectors.toMap(BranchDto::getProjectUuid, BranchDto::getUuid)); + } private static Map buildQualityGateStatuses(List measures) { return ImmutableMap.copyOf(measures.stream() .collect(Collectors.toMap(LiveMeasureDto::getComponentUuid, LiveMeasureDto::getDataAsString))); } + public String mainBranchUuidForProjectUuid(String projectUuid) { + String branchUuid = branchUuidByProjectUuids.get(projectUuid); + if(branchUuid==null){ + throw new IllegalStateException("Project must have a corresponding main branch."); + } + return branchUuid; + + + } + static class Builder { - private List projects; + + private List projects; + private List branches; private List projectLinks; private List snapshots; private List qualityGates; @@ -97,11 +118,16 @@ class SearchMyProjectsData { // enforce method constructor } - Builder setProjects(List projects) { + Builder setProjects(List projects) { this.projects = projects; return this; } + Builder setBranches(List branches) { + this.branches = branches; + return this; + } + public Builder setProjectLinks(List projectLinks) { this.projectLinks = projectLinks; return this; @@ -124,6 +150,7 @@ class SearchMyProjectsData { SearchMyProjectsData build() { requireNonNull(projects); + requireNonNull(branches); requireNonNull(projectLinks); requireNonNull(snapshots); requireNonNull(qualityGates); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/SearchMyProjectsDataTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/SearchMyProjectsDataTest.java index 58d0d4b42ba..55c3bf45b14 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/SearchMyProjectsDataTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/project/ws/SearchMyProjectsDataTest.java @@ -45,6 +45,7 @@ public class SearchMyProjectsDataTest { public void fail_if_projects_links_are_not_provided() { Builder builder = underTest .setProjects(emptyList()) + .setBranches(emptyList()) .setProjectLinks(null) .setSnapshots(emptyList()) .setQualityGates(emptyList()) @@ -57,6 +58,7 @@ public class SearchMyProjectsDataTest { public void fail_if_snapshots_are_not_provided() { Builder builder = underTest .setProjects(emptyList()) + .setBranches(emptyList()) .setProjectLinks(emptyList()) .setSnapshots(null) .setQualityGates(emptyList()) @@ -68,7 +70,7 @@ public class SearchMyProjectsDataTest { @Test public void fail_if_quality_gates_are_not_provided() { Builder builder = underTest - .setProjects(emptyList()) + .setBranches(emptyList()) .setProjectLinks(emptyList()) .setSnapshots(emptyList()) .setQualityGates(null); @@ -79,7 +81,7 @@ public class SearchMyProjectsDataTest { @Test public void fail_if_total_number_of_projects_is_not_provided() { Builder builder = underTest - .setProjects(emptyList()) + .setBranches(emptyList()) .setProjectLinks(emptyList()) .setSnapshots(emptyList()) .setQualityGates(emptyList()) -- 2.39.5