From: Benjamin Campomenosi <109955405+benjamin-campomenosi-sonarsource@users.noreply.github.com> Date: Thu, 6 Jul 2023 09:16:27 +0000 (+0200) Subject: SONAR-19558 - Refactor rest of tests in developer server X-Git-Tag: 10.2.0.77647~454 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d92140b71b2684ce1c93e6d5971eba92faf45fc8;p=sonarqube.git SONAR-19558 - Refactor rest of tests in developer server --- diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/project/DeletedProject.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/project/DeletedProject.java new file mode 100644 index 00000000000..965ec4f94e9 --- /dev/null +++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/project/DeletedProject.java @@ -0,0 +1,36 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.project; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * This record is used to refresh application/portfolio after the deletion of a project / portfolio + * @param project could refer to a project or a portfolio deleted + * @param mainBranchUuid refer to the main branch of the project deleted, is null when this record is used for a portfolio + */ +public record DeletedProject(Project project, @Nullable String mainBranchUuid) { + public DeletedProject(Project project, String mainBranchUuid) { + this.project = checkNotNull(project, "project can't be null"); + this.mainBranchUuid = mainBranchUuid; + } +} diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListener.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListener.java index d30709aa1e6..f16ea78b849 100644 --- a/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListener.java +++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListener.java @@ -27,7 +27,7 @@ public interface ProjectLifeCycleListener { /** * This method is called after the specified projects have been deleted. */ - void onProjectsDeleted(Set projects); + void onProjectsDeleted(Set projects); /** * This method is called after the specified projects have been deleted. diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListeners.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListeners.java index 4613e71b1b1..9b0ba01ccc2 100644 --- a/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListeners.java +++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListeners.java @@ -30,7 +30,7 @@ public interface ProjectLifeCycleListeners { * This method ensures all {@link ProjectLifeCycleListener} implementations are called, even if one or more of * them fail with an exception. */ - void onProjectsDeleted(Set projects); + void onProjectsDeleted(Set projects); /** * This method is called after the specified project branches have been deleted and will call method diff --git a/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java b/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java index 78a4b644cc8..c80d6110ce5 100644 --- a/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java +++ b/server/sonar-webserver-api/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java @@ -50,7 +50,7 @@ public class ProjectLifeCycleListenersImpl implements ProjectLifeCycleListeners } @Override - public void onProjectsDeleted(Set projects) { + public void onProjectsDeleted(Set projects) { checkNotNull(projects, "projects can't be null"); if (projects.isEmpty()) { return; diff --git a/server/sonar-webserver-api/src/test/java/org/sonar/server/project/ProjectLifeCycleListenersImplTest.java b/server/sonar-webserver-api/src/test/java/org/sonar/server/project/ProjectLifeCycleListenersImplTest.java index 8f90941e936..5caab5128b8 100644 --- a/server/sonar-webserver-api/src/test/java/org/sonar/server/project/ProjectLifeCycleListenersImplTest.java +++ b/server/sonar-webserver-api/src/test/java/org/sonar/server/project/ProjectLifeCycleListenersImplTest.java @@ -33,6 +33,8 @@ import org.mockito.Mockito; import org.sonar.core.util.stream.MoreCollectors; import static java.util.Collections.singleton; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doThrow; @@ -74,14 +76,14 @@ public class ProjectLifeCycleListenersImplTest { } @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectsDeleted_does_not_fail_if_there_is_no_listener(Set projects) { - underTestNoListeners.onProjectsDeleted(projects); + @UseDataProvider("oneOrManyDeletedProjects") + public void onProjectsDeleted_does_not_fail_if_there_is_no_listener(Set projects) { + assertThatCode(() -> underTestNoListeners.onProjectsDeleted(projects)).doesNotThrowAnyException(); } @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectsDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set projects) { + @UseDataProvider("oneOrManyDeletedProjects") + public void onProjectsDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set projects) { InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); underTestWithListeners.onProjectsDeleted(projects); @@ -93,8 +95,8 @@ public class ProjectLifeCycleListenersImplTest { } @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set projects) { + @UseDataProvider("oneOrManyDeletedProjects") + public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set projects) { InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); doThrow(new RuntimeException("Faking listener2 throwing an exception")) .when(listener2) @@ -109,8 +111,8 @@ public class ProjectLifeCycleListenersImplTest { } @Test - @UseDataProvider("oneOrManyProjects") - public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set projects) { + @UseDataProvider("oneOrManyDeletedProjects") + public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set projects) { InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3); doThrow(new Error("Faking listener2 throwing an Error")) .when(listener2) @@ -204,7 +206,16 @@ public class ProjectLifeCycleListenersImplTest { {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueProject()).collect(MoreCollectors.toSet())} }; } - // SDSDS + + @DataProvider + public static Object[][] oneOrManyDeletedProjects() { + return new Object[][] { + {singleton(newUniqueProject())}, + {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> new DeletedProject(newUniqueProject(), "branch_" + i)) + .collect(MoreCollectors.toSet())} + }; + } + @Test public void onProjectsRekeyed_throws_NPE_if_set_is_null() { diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java index 4d096c1af82..258ad145f70 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/BulkDeleteActionIT.java @@ -22,7 +22,9 @@ package org.sonar.server.project.ws; import java.net.HttpURLConnection; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -40,13 +42,16 @@ import org.sonar.core.util.stream.MoreCollectors; 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.PortfolioData; import org.sonar.db.component.ProjectData; import org.sonar.db.entity.EntityDto; import org.sonar.db.portfolio.PortfolioDto; import org.sonar.db.project.ProjectDto; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.project.DeletedProject; import org.sonar.server.project.Project; import org.sonar.server.project.ProjectLifeCycleListeners; import org.sonar.server.tester.UserSessionRule; @@ -88,8 +93,10 @@ public class BulkDeleteActionIT { @Test public void delete_projects() { userSession.addPermission(ADMINISTER); - ProjectDto project1ToDelete = db.components().insertPrivateProject().getProjectDto(); - ProjectDto project2ToDelete = db.components().insertPrivateProject().getProjectDto(); + ProjectData projectData1ToDelete = db.components().insertPrivateProject(); + ProjectDto project1ToDelete = projectData1ToDelete.getProjectDto(); + ProjectData projectData2ToDelete = db.components().insertPrivateProject(); + ProjectDto project2ToDelete = projectData2ToDelete.getProjectDto(); ComponentDto toKeep = db.components().insertPrivateProject().getMainBranchComponent(); TestResponse result = ws.newRequest() @@ -99,21 +106,21 @@ public class BulkDeleteActionIT { assertThat(result.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); assertThat(result.getInput()).isEmpty(); verifyEntityDeleted(project1ToDelete, project2ToDelete); - verifyListenersOnProjectsDeleted(project1ToDelete, project2ToDelete); + verifyListenersOnProjectsDeleted(projectData1ToDelete, projectData2ToDelete); } @Test public void delete_projects_by_keys() { userSession.addPermission(ADMINISTER); - ProjectDto toDeleteInOrg1 = db.components().insertPrivateProject().getProjectDto(); - ProjectDto toDeleteInOrg2 = db.components().insertPrivateProject().getProjectDto(); + ProjectData toDeleteInOrg1 = db.components().insertPrivateProject(); + ProjectData toDeleteInOrg2 = db.components().insertPrivateProject(); ComponentDto toKeep = db.components().insertPrivateProject().getMainBranchComponent(); ws.newRequest() - .setParam(PARAM_PROJECTS, toDeleteInOrg1.getKey() + "," + toDeleteInOrg2.getKey()) + .setParam(PARAM_PROJECTS, toDeleteInOrg1.getProjectDto().getKey() + "," + toDeleteInOrg2.getProjectDto().getKey()) .execute(); - verifyEntityDeleted(toDeleteInOrg1, toDeleteInOrg2); + verifyEntityDeleted(toDeleteInOrg1.getProjectDto(), toDeleteInOrg2.getProjectDto()); verifyListenersOnProjectsDeleted(toDeleteInOrg1, toDeleteInOrg2); } @@ -136,14 +143,14 @@ public class BulkDeleteActionIT { @Test public void projects_that_dont_exist_are_ignored_and_dont_break_bulk_deletion() { userSession.addPermission(ADMINISTER); - ProjectDto toDelete1 = db.components().insertPrivateProject().getProjectDto(); - ProjectDto toDelete2 = db.components().insertPrivateProject().getProjectDto(); + ProjectData toDelete1 = db.components().insertPrivateProject(); + ProjectData toDelete2 = db.components().insertPrivateProject(); ws.newRequest() - .setParam("projects", toDelete1.getKey() + ",missing," + toDelete2.getKey() + ",doesNotExist") + .setParam("projects", toDelete1.getProjectDto().getKey() + ",missing," + toDelete2.getProjectDto().getKey() + ",doesNotExist") .execute(); - verifyEntityDeleted(toDelete1, toDelete2); + verifyEntityDeleted(toDelete1.getProjectDto(), toDelete2.getProjectDto()); verifyListenersOnProjectsDeleted(toDelete1, toDelete2); } @@ -167,61 +174,61 @@ public class BulkDeleteActionIT { .execute(); verifyEntityDeleted(oldProject); - verifyListenersOnProjectsDeleted(oldProject); + verifyListenersOnProjectsDeleted(oldProjectData); } @Test public void provisioned_projects() { userSession.logIn().addPermission(ADMINISTER); - ProjectDto provisionedProject = db.components().insertPrivateProject().getProjectDto(); + ProjectData provisionedProject = db.components().insertPrivateProject(); ProjectData analyzedProjectData = db.components().insertPrivateProject(); ProjectDto analyzedProject = analyzedProjectData.getProjectDto(); db.components().insertSnapshot(newAnalysis(analyzedProjectData.getMainBranchComponent())); - ws.newRequest().setParam(PARAM_PROJECTS, provisionedProject.getKey() + "," + analyzedProject.getKey()).setParam(PARAM_ON_PROVISIONED_ONLY, "true").execute(); + ws.newRequest().setParam(PARAM_PROJECTS, provisionedProject.getProjectDto().getKey() + "," + analyzedProject.getKey()).setParam(PARAM_ON_PROVISIONED_ONLY, "true").execute(); - verifyEntityDeleted(provisionedProject); + verifyEntityDeleted(provisionedProject.getProjectDto()); verifyListenersOnProjectsDeleted(provisionedProject); } @Test public void delete_more_than_50_projects() { userSession.logIn().addPermission(ADMINISTER); - ProjectDto[] projects = IntStream.range(0, 55).mapToObj(i -> db.components().insertPrivateProject().getProjectDto()).toArray(ProjectDto[]::new); + ProjectData[] projects = IntStream.range(0, 55).mapToObj(i -> db.components().insertPrivateProject()).toArray(ProjectData[]::new); - List projectKeys = Stream.of(projects).map(ProjectDto::getKey).collect(Collectors.toList()); + List projectKeys = Stream.of(projects).map(ProjectData::getProjectDto).map(ProjectDto::getKey).collect(Collectors.toList()); ws.newRequest().setParam(PARAM_PROJECTS, String.join(",", projectKeys)).execute(); - verifyEntityDeleted(projects); + verifyEntityDeleted(Stream.of(projects).map(ProjectData::getProjectDto).toArray(ProjectDto[]::new)); verifyListenersOnProjectsDeleted(projects); } @Test public void projects_and_views() { userSession.logIn().addPermission(ADMINISTER); - ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + ProjectData project = db.components().insertPrivateProject(); ComponentDto view = db.components().insertPrivatePortfolio(); PortfolioDto portfolioDto = db.components().getPortfolioDto(view); ws.newRequest() - .setParam(PARAM_PROJECTS, project.getKey() + "," + view.getKey()) + .setParam(PARAM_PROJECTS, project.getProjectDto().getKey() + "," + view.getKey()) .setParam(PARAM_QUALIFIERS, String.join(",", Qualifiers.PROJECT, Qualifiers.VIEW)) .execute(); - verifyEntityDeleted(project, portfolioDto); + verifyEntityDeleted(project.getProjectDto(), portfolioDto); verifyListenersOnProjectsDeleted(project, portfolioDto); } @Test public void delete_by_key_query_with_partial_match_case_insensitive() { userSession.logIn().addPermission(ADMINISTER); - ProjectDto matchKeyProject = db.components().insertPrivateProject(p -> p.setKey("project-_%-key")).getProjectDto(); - ProjectDto matchUppercaseKeyProject = db.components().insertPrivateProject(p -> p.setKey("PROJECT-_%-KEY")).getProjectDto(); + ProjectData matchKeyProject = db.components().insertPrivateProject(p -> p.setKey("project-_%-key")); + ProjectData matchUppercaseKeyProject = db.components().insertPrivateProject(p -> p.setKey("PROJECT-_%-KEY")); ProjectDto noMatchProject = db.components().insertPrivateProject(p -> p.setKey("project-key-without-escaped-characters")).getProjectDto(); ws.newRequest().setParam(Param.TEXT_QUERY, "JeCt-_%-k").execute(); - verifyEntityDeleted(matchKeyProject, matchUppercaseKeyProject); + verifyEntityDeleted(matchKeyProject.getProjectDto(), matchUppercaseKeyProject.getProjectDto()); verifyListenersOnProjectsDeleted(matchKeyProject, matchUppercaseKeyProject); } @@ -239,7 +246,7 @@ public class BulkDeleteActionIT { .execute(); verify(componentCleanerService, times(1_000)).deleteEntity(any(DbSession.class), any(EntityDto.class)); - ArgumentCaptor> projectsCaptor = ArgumentCaptor.forClass(Set.class); + ArgumentCaptor> projectsCaptor = ArgumentCaptor.forClass(Set.class); verify(projectLifeCycleListeners).onProjectsDeleted(projectsCaptor.capture()); assertThat(projectsCaptor.getValue()).hasSize(1_000); } @@ -247,9 +254,9 @@ public class BulkDeleteActionIT { @Test public void projectLifeCycleListeners_onProjectsDeleted_called_even_if_delete_fails() { userSession.logIn().addPermission(ADMINISTER); - ProjectDto project1 = db.components().insertPrivateProject().getProjectDto(); - ProjectDto project2 = db.components().insertPrivateProject().getProjectDto(); - ProjectDto project3 = db.components().insertPrivateProject().getProjectDto(); + ProjectData project1 = db.components().insertPrivateProject(); + ProjectData project2 = db.components().insertPrivateProject(); + ProjectData project3 = db.components().insertPrivateProject(); ComponentCleanerService componentCleanerService = mock(ComponentCleanerService.class); RuntimeException expectedException = new RuntimeException("Faking delete failing on 2nd project"); doNothing() @@ -259,7 +266,7 @@ public class BulkDeleteActionIT { try { ws.newRequest() - .setParam("projects", project1.getKey() + "," + project2.getKey() + "," + project3.getKey()) + .setParam("projects", project1.getProjectDto().getKey() + "," + project2.getProjectDto().getKey() + "," + project3.getProjectDto().getKey()) .execute(); } catch (RuntimeException e) { assertThat(e).isSameAs(expectedException); @@ -270,14 +277,14 @@ public class BulkDeleteActionIT { @Test public void global_administrator_deletes_projects_by_keys() { userSession.logIn().addPermission(ADMINISTER); - ProjectDto toDelete1 = db.components().insertPrivateProject().getProjectDto(); - ProjectDto toDelete2 = db.components().insertPrivateProject().getProjectDto(); + ProjectData toDelete1 = db.components().insertPrivateProject(); + ProjectData toDelete2 = db.components().insertPrivateProject(); ws.newRequest() - .setParam("projects", toDelete1.getKey() + "," + toDelete2.getKey()) + .setParam("projects", toDelete1.getProjectDto().getKey() + "," + toDelete2.getProjectDto().getKey()) .execute(); - verifyEntityDeleted(toDelete1, toDelete2); + verifyEntityDeleted(toDelete1.getProjectDto(), toDelete2.getProjectDto()); verifyListenersOnProjectsDeleted(toDelete1, toDelete2); } @@ -325,8 +332,25 @@ public class BulkDeleteActionIT { verifyNoMoreInteractions(componentCleanerService); } - private void verifyListenersOnProjectsDeleted(EntityDto... entityDtos) { + private void verifyListenersOnProjectsDeleted(ProjectData projectData, PortfolioDto portfolioDto) { + Map entityWithBranh = new HashMap<>(); + entityWithBranh.put(projectData.getProjectDto(), projectData.getMainBranchDto().getUuid()); + entityWithBranh.put(portfolioDto, null); + + verifyListenersOnProjectsDeleted(entityWithBranh); + } + + private void verifyListenersOnProjectsDeleted(ProjectData... projectData) { + verifyListenersOnProjectsDeleted(Arrays.stream(projectData).collect(Collectors.toMap(ProjectData::getProjectDto, data -> data.getMainBranchDto().getUuid()))); + } + + private void verifyListenersOnProjectsDeleted(PortfolioData... portfolioData) { + verifyListenersOnProjectsDeleted(Arrays.stream(portfolioData).collect(Collectors.toMap(PortfolioData::getPortfolioDto, null))); + } + + private void verifyListenersOnProjectsDeleted(Map entityWithBranchUuid) { verify(projectLifeCycleListeners) - .onProjectsDeleted(Arrays.stream(entityDtos).map(Project::from).collect(Collectors.toSet())); + .onProjectsDeleted(entityWithBranchUuid.entrySet() + .stream().map(entry -> new DeletedProject(Project.from(entry.getKey()), entry.getValue())).collect(Collectors.toSet())); } } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java index 035b3ef9ffc..fec4fc61215 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/project/ws/DeleteActionIT.java @@ -39,6 +39,7 @@ import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.es.TestIndexers; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.project.DeletedProject; import org.sonar.server.project.Project; import org.sonar.server.project.ProjectLifeCycleListeners; import org.sonar.server.tester.UserSessionRule; @@ -80,13 +81,15 @@ public class DeleteActionIT { @Test public void global_administrator_deletes_project_by_key() { ProjectData projectData = db.components().insertPrivateProject(); - ComponentDto project = projectData.getMainBranchComponent(); + ComponentDto rootComponent = projectData.getMainBranchComponent(); userSessionRule.logIn().addPermission(GlobalPermission.ADMINISTER); - call(tester.newRequest().setParam(PARAM_PROJECT, project.getKey())); + call(tester.newRequest().setParam(PARAM_PROJECT, rootComponent.getKey())); - assertThat(verifyDeletedKey()).isEqualTo(project.getKey()); - verify(projectLifeCycleListeners).onProjectsDeleted(singleton(Project.from(projectData.getProjectDto()))); + assertThat(verifyDeletedKey()).isEqualTo(rootComponent.getKey()); + Project from = Project.from(projectData.getProjectDto()); + String mainBranchUuid = projectData.getMainBranchDto().getUuid(); + verify(projectLifeCycleListeners).onProjectsDeleted(singleton(new DeletedProject(from, mainBranchUuid))); } @Test @@ -98,7 +101,7 @@ public class DeleteActionIT { call(tester.newRequest().setParam(PARAM_PROJECT, project.getKey())); assertThat(verifyDeletedKey()).isEqualTo(project.getKey()); - verify(projectLifeCycleListeners).onProjectsDeleted(singleton(Project.from(projectData.getProjectDto()))); + verify(projectLifeCycleListeners).onProjectsDeleted(singleton(new DeletedProject(Project.from(projectData.getProjectDto()),projectData.getMainBranchDto().getUuid()))); } @Test diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java index 57d33bc5ff8..fdc1793fd8c 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java @@ -20,9 +20,11 @@ package org.sonar.server.project.ws; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableSet; import java.util.Date; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -38,11 +40,13 @@ import org.sonar.api.utils.DateUtils; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentQuery; import org.sonar.db.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.server.component.ComponentCleanerService; +import org.sonar.server.project.DeletedProject; import org.sonar.server.project.Project; import org.sonar.server.project.ProjectLifeCycleListeners; import org.sonar.server.project.Visibility; @@ -118,7 +122,7 @@ public class BulkDeleteAction implements ProjectsWsAction { action.createParam(PARAM_VISIBILITY) .setDescription("Filter the projects that should be visible to everyone (%s), or only specific user/groups (%s).
" + - "If no visibility is specified, the default project visibility will be used.", + "If no visibility is specified, the default project visibility will be used.", Visibility.PUBLIC.getLabel(), Visibility.PRIVATE.getLabel()) .setRequired(false) .setInternal(true) @@ -154,12 +158,22 @@ public class BulkDeleteAction implements ProjectsWsAction { try { entities.forEach(p -> componentCleanerService.deleteEntity(dbSession, p)); } finally { - projectLifeCycleListeners.onProjectsDeleted(entities.stream().map(Project::from).collect(Collectors.toSet())); + callDeleteListeners(dbSession, componentDtos, entities); } } response.noContent(); } + private void callDeleteListeners(DbSession dbSession, Set componentDtos, List entities) { + Set entityUuids = entities.stream().map(EntityDto::getUuid).collect(toSet()); + Map mainBranchUuidByEntityUuid = dbClient.branchDao().selectMainBranchesByProjectUuids(dbSession, entityUuids).stream() + .collect(Collectors.toMap(BranchDto::getProjectUuid, BranchDto::getUuid)); + + ImmutableSet deletedProjects = entities.stream().map(entity -> new DeletedProject(Project.from(entity), mainBranchUuidByEntityUuid.get(entity.getUuid()))) + .collect(MoreCollectors.toSet(componentDtos.size())); + projectLifeCycleListeners.onProjectsDeleted(deletedProjects); + } + private static void checkAtLeastOneParameterIsPresent(SearchRequest searchRequest) { boolean analyzedBeforePresent = !Strings.isNullOrEmpty(searchRequest.getAnalyzedBefore()); List projects = searchRequest.getProjects(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java index 3fc9097d398..7b0e6742df7 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/project/ws/DeleteAction.java @@ -25,10 +25,12 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.component.BranchDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.db.project.ProjectDto; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.project.DeletedProject; import org.sonar.server.project.Project; import org.sonar.server.project.ProjectLifeCycleListeners; import org.sonar.server.user.UserSession; @@ -80,9 +82,10 @@ public class DeleteAction implements ProjectsWsAction { try (DbSession dbSession = dbClient.openSession(false)) { ProjectDto project = componentFinder.getProjectByKey(dbSession, key); + BranchDto mainBranch = componentFinder.getMainBranch(dbSession, project); checkPermission(project); componentCleanerService.deleteEntity(dbSession, project); - projectLifeCycleListeners.onProjectsDeleted(singleton(Project.fromProjectDtoWithTags(project))); + projectLifeCycleListeners.onProjectsDeleted(singleton(new DeletedProject(Project.fromProjectDtoWithTags(project), mainBranch.getUuid()))); } response.noContent();