diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2023-06-16 14:48:59 -0500 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-06-29 20:05:14 +0000 |
commit | 114a4deec2e278438cb9db6666b9bc8dfc46ab2c (patch) | |
tree | 046a3509a9af9f2e3b4052200078f01cb18ce698 /server/sonar-db-dao | |
parent | 63fc7d901eaacd42e9a40099906c38ae2aa779d4 (diff) | |
download | sonarqube-114a4deec2e278438cb9db6666b9bc8dfc46ab2c.tar.gz sonarqube-114a4deec2e278438cb9db6666b9bc8dfc46ab2c.zip |
SONAR-19558 Refactor 'issues', 'issue_changes', Components and view indexes
Diffstat (limited to 'server/sonar-db-dao')
23 files changed, 199 insertions, 153 deletions
diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java index b9b9934f3cf..688190bac7b 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentDaoIT.java @@ -879,11 +879,11 @@ public class ComponentDaoIT { db.components().insertComponent(newProjectCopy(project1, subView)); ComponentDto viewWithoutProject = db.components().insertPrivatePortfolio(); - assertThat(underTest.selectProjectsFromView(dbSession, view.uuid(), view.uuid())).containsExactlyInAnyOrder(project1.uuid()); - assertThat(underTest.selectProjectsFromView(dbSession, viewWithSubView.uuid(), viewWithSubView.uuid())).containsExactlyInAnyOrder(project1.uuid(), project2.uuid()); - assertThat(underTest.selectProjectsFromView(dbSession, subView.uuid(), viewWithSubView.uuid())).containsExactlyInAnyOrder(project1.uuid()); - assertThat(underTest.selectProjectsFromView(dbSession, viewWithoutProject.uuid(), viewWithoutProject.uuid())).isEmpty(); - assertThat(underTest.selectProjectsFromView(dbSession, "Unknown", "Unknown")).isEmpty(); + assertThat(underTest.selectProjectBranchUuidsFromView(dbSession, view.uuid(), view.uuid())).containsExactlyInAnyOrder(project1.uuid()); + assertThat(underTest.selectProjectBranchUuidsFromView(dbSession, viewWithSubView.uuid(), viewWithSubView.uuid())).containsExactlyInAnyOrder(project1.uuid(), project2.uuid()); + assertThat(underTest.selectProjectBranchUuidsFromView(dbSession, subView.uuid(), viewWithSubView.uuid())).containsExactlyInAnyOrder(project1.uuid()); + assertThat(underTest.selectProjectBranchUuidsFromView(dbSession, viewWithoutProject.uuid(), viewWithoutProject.uuid())).isEmpty(); + assertThat(underTest.selectProjectBranchUuidsFromView(dbSession, "Unknown", "Unknown")).isEmpty(); } @Test @@ -915,8 +915,8 @@ public class ComponentDaoIT { ComponentDto subView2 = db.components().insertComponent(newSubPortfolio(view, "ABC", "ABC-key")); db.components().insertComponent(newProjectCopy(project3, subView2)); - assertThat(underTest.selectProjectsFromView(dbSession, subView1.uuid(), view.uuid())).containsExactlyInAnyOrder(project1.uuid(), project2.uuid()); - assertThat(underTest.selectProjectsFromView(dbSession, subView2.uuid(), view.uuid())).containsExactlyInAnyOrder(project3.uuid()); + assertThat(underTest.selectProjectBranchUuidsFromView(dbSession, subView1.uuid(), view.uuid())).containsExactlyInAnyOrder(project1.uuid(), project2.uuid()); + assertThat(underTest.selectProjectBranchUuidsFromView(dbSession, subView2.uuid(), view.uuid())).containsExactlyInAnyOrder(project3.uuid()); } @Test diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentKeyUpdaterDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentKeyUpdaterDaoIT.java index 13d60db267f..e81aa17ef53 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentKeyUpdaterDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/component/ComponentKeyUpdaterDaoIT.java @@ -59,7 +59,7 @@ public class ComponentKeyUpdaterDaoIT { public void updateKey_changes_the_key_of_tree_of_components() { populateSomeData(); - underTest.updateKey(dbSession, "A", "struts:core"); + underTest.updateKey(dbSession, "A", "org.struts:struts", "struts:core"); dbSession.commit(); assertThat(db.select("select uuid as \"UUID\", kee as \"KEE\" from components")) @@ -73,9 +73,7 @@ public class ComponentKeyUpdaterDaoIT { @Test public void updateKey_updates_disabled_components() { - ComponentDto project = db.components().insertComponent( - newPrivateProjectDto("A") - .setKey("my_project")); + ComponentDto project = db.components().insertPrivateProject("A", p -> p.setKey("my_project")).getMainBranchComponent(); ComponentDto directory = db.components().insertComponent( newDirectory(project, "B") .setKey("my_project:directory")); @@ -83,7 +81,7 @@ public class ComponentKeyUpdaterDaoIT { ComponentDto inactiveDirectory = db.components().insertComponent(newDirectory(project, "/inactive_directory").setKey("my_project:inactive_directory").setEnabled(false)); db.components().insertComponent(newFileDto(project, inactiveDirectory).setKey("my_project:inactive_directory/file").setEnabled(false)); - underTest.updateKey(dbSession, "A", "your_project"); + underTest.updateKey(dbSession, "A", "my_project", "your_project"); dbSession.commit(); List<ComponentDto> result = dbClient.componentDao().selectByBranchUuid("A", dbSession); @@ -107,7 +105,7 @@ public class ComponentKeyUpdaterDaoIT { assertThat(dbClient.componentDao().selectByBranchUuid(branch.uuid(), dbSession)).hasSize(prComponentCount); String newProjectKey = "newKey"; - underTest.updateKey(dbSession, project.uuid(), newProjectKey); + underTest.updateKey(dbSession, project.uuid(), project.getKey(), newProjectKey); assertThat(dbClient.componentDao().selectByKey(dbSession, oldProjectKey)).isEmpty(); assertThat(dbClient.componentDao().selectByKey(dbSession, newProjectKey)).isPresent(); @@ -133,7 +131,7 @@ public class ComponentKeyUpdaterDaoIT { assertThat(dbClient.componentDao().selectByBranchUuid(pullRequest.uuid(), dbSession)).hasSize(prComponentCount); String newProjectKey = "newKey"; - underTest.updateKey(dbSession, project.uuid(), newProjectKey); + underTest.updateKey(dbSession, project.uuid(), project.getKey(), newProjectKey); assertThat(dbClient.componentDao().selectByKey(dbSession, oldProjectKey)).isEmpty(); assertThat(dbClient.componentDao().selectByKey(dbSession, newProjectKey)).isPresent(); @@ -150,19 +148,18 @@ public class ComponentKeyUpdaterDaoIT { public void updateKey_throws_IAE_if_component_with_specified_key_does_not_exist() { populateSomeData(); - assertThatThrownBy(() -> underTest.updateKey(dbSession, "A", "foo:struts-core")) + assertThatThrownBy(() -> underTest.updateKey(dbSession, "A", "org.struts:struts", "foo:struts-core")) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Impossible to update key: a component with key \"foo:struts-core\" already exists."); } @Test public void updateKey_throws_IAE_when_sub_component_key_is_too_long() { - ComponentDto project = newPrivateProjectDto("project-uuid").setKey("old-project-key"); - db.components().insertComponent(project); + ComponentDto project = db.components().insertPrivateProject("project-uuid", p -> p.setKey("old-project-key")).getMainBranchComponent(); db.components().insertComponent(newFileDto(project).setKey("old-project-key:file")); String newLongProjectKey = Strings.repeat("a", 400); - assertThatThrownBy(() -> underTest.updateKey(dbSession, project.uuid(), newLongProjectKey)) + assertThatThrownBy(() -> underTest.updateKey(dbSession, project.uuid(), project.getKey(), newLongProjectKey)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Component key length (405) is longer than the maximum authorized (400). '" + newLongProjectKey + ":file' was provided."); } @@ -175,12 +172,11 @@ public class ComponentKeyUpdaterDaoIT { @Test public void updateKey_callsAuditPersister() { - db.components().insertComponent(newPrivateProjectDto("A").setKey("my_project")); + db.components().insertPrivateProject("A", p -> p.setKey("my_project")); - underTestWithAuditPersister.updateKey(dbSession, "A", "your_project"); + underTestWithAuditPersister.updateKey(dbSession, "A", "my_project", "your_project"); - verify(auditPersister, times(1)) - .componentKeyUpdate(any(DbSession.class), any(ComponentKeyNewValue.class), anyString()); + verify(auditPersister, times(1)).componentKeyUpdate(any(DbSession.class), any(ComponentKeyNewValue.class), anyString()); } private void populateSomeData() { diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/component/SnapshotDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/component/SnapshotDaoIT.java index b0bf23234ad..2361b2e81ed 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/component/SnapshotDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/component/SnapshotDaoIT.java @@ -164,36 +164,8 @@ public class SnapshotDaoIT { } @Test - public void selectLastAnalysisDateByProject_takes_all_branches_into_account() { - ComponentDto firstProject = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto branch1 = db.components().insertProjectBranch(firstProject); - ComponentDto branch2 = db.components().insertProjectBranch(firstProject); - - dbClient.snapshotDao().insert(dbSession, newAnalysis(firstProject).setLast(false).setCreatedAt(1L)); - dbClient.snapshotDao().insert(dbSession, newAnalysis(branch1).setLast(false).setCreatedAt(2L)); - dbClient.snapshotDao().insert(dbSession, newAnalysis(branch2).setLast(false).setCreatedAt(10L)); - - dbClient.snapshotDao().insert(dbSession, newAnalysis(firstProject).setLast(true).setCreatedAt(7L)); - dbClient.snapshotDao().insert(dbSession, newAnalysis(branch1).setLast(true).setCreatedAt(8L)); - dbClient.snapshotDao().insert(dbSession, newAnalysis(branch2).setLast(true).setCreatedAt(9L)); - - Optional<Long> date = underTest.selectLastAnalysisDateByProject(dbSession, firstProject.uuid()); - - assertThat(date).contains(9L); - } - - @Test - public void selectLastAnalysisDateByProject_is_empty_if_no_snapshot() { - ComponentDto firstProject = db.components().insertPrivateProject().getMainBranchComponent(); - ComponentDto branch1 = db.components().insertProjectBranch(firstProject); - ComponentDto branch2 = db.components().insertProjectBranch(firstProject); - - assertThat(underTest.selectLastAnalysisDateByProject(dbSession, firstProject.uuid())).isEmpty(); - } - - @Test public void selectLastAnalysisDateByProjects_is_empty_if_no_project_passed() { - assertThat(underTest.selectLastAnalysisDateByProjects(dbSession, emptyList())).isEmpty(); + assertThat(underTest.selectLastAnalysisDateByProjectUuids(dbSession, emptyList())).isEmpty(); } @Test @@ -213,7 +185,7 @@ public class SnapshotDaoIT { dbClient.snapshotDao().insert(dbSession, newAnalysis(branch2).setLast(false).setCreatedAt(5L)); dbClient.snapshotDao().insert(dbSession, newAnalysis(branch1).setLast(true).setCreatedAt(4L)); - List<ProjectLastAnalysisDateDto> lastAnalysisByProject = underTest.selectLastAnalysisDateByProjects(dbSession, + List<ProjectLastAnalysisDateDto> lastAnalysisByProject = underTest.selectLastAnalysisDateByProjectUuids(dbSession, List.of(project1.uuid(), project2.uuid(), project3.uuid(), "non-existing")); assertThat(lastAnalysisByProject).extracting(ProjectLastAnalysisDateDto::getProjectUuid, ProjectLastAnalysisDateDto::getDate) @@ -230,7 +202,7 @@ public class SnapshotDaoIT { dbClient.snapshotDao().insert(dbSession, newAnalysis(portfolio).setLast(true).setCreatedAt(2L)); dbClient.snapshotDao().insert(dbSession, newAnalysis(branch1).setLast(true).setCreatedAt(3L)); - List<ProjectLastAnalysisDateDto> lastAnalysisByProject = underTest.selectLastAnalysisDateByProjects(dbSession, + List<ProjectLastAnalysisDateDto> lastAnalysisByProject = underTest.selectLastAnalysisDateByProjectUuids(dbSession, List.of(project1.uuid(), portfolio.uuid())); assertThat(lastAnalysisByProject).extracting(ProjectLastAnalysisDateDto::getProjectUuid, ProjectLastAnalysisDateDto::getDate) diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java index 7b54d98409c..3f6276ac35c 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/entity/EntityDaoIT.java @@ -27,8 +27,12 @@ import org.junit.Test; import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; +import org.sonar.db.component.BranchDto; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.ProjectData; import org.sonar.db.portfolio.PortfolioDto; +import org.sonar.db.project.ProjectDto; import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; @@ -42,6 +46,42 @@ public class EntityDaoIT { private final EntityDao entityDao = new EntityDao(); @Test + public void selectEntityByComponentUuid_shouldReturnProjectEntityBasedOnComponent() { + ProjectDto project = db.components().insertPrivateProject().getProjectDto(); + BranchDto branchDto = db.components().insertProjectBranch(project); + ComponentDto fileInBranch = db.components().insertFile(branchDto); + + assertThat(entityDao.selectByComponentUuid(db.getSession(), fileInBranch.uuid()).get()) + .extracting(EntityDto::getUuid, EntityDto::getKey) + .containsOnly(project.getUuid(), project.getKey()); + } + + @Test + public void selectEntityByComponentUuid_shouldReturnPortfolioEntityBasedOnComponent() { + PortfolioDto portfolio = db.components().insertPublicPortfolioDto(); + assertThat(entityDao.selectByComponentUuid(db.getSession(), portfolio.getUuid()).get()) + .extracting(EntityDto::getUuid, EntityDto::getKey) + .containsOnly(portfolio.getUuid(), portfolio.getKey()); + } + + @Test + public void selectEntityByComponentUuid_whenPortfolioWithHierarchy_shouldReturnPortfolioEntityBasedOnComponent() { + ComponentDto projectBranch = db.components().insertPublicProject().getMainBranchComponent(); + ComponentDto portfolio = db.components().insertPublicPortfolio(); + ComponentDto subPortfolio = db.components().insertSubportfolio(portfolio); + ComponentDto projectCopy = db.components().insertComponent(ComponentTesting.newProjectCopy(projectBranch, subPortfolio)); + + assertThat(entityDao.selectByComponentUuid(db.getSession(), projectCopy.uuid()).get()) + .extracting(EntityDto::getUuid, EntityDto::getKey) + .containsOnly(portfolio.uuid(), portfolio.getKey()); + } + + @Test + public void selectEntityByComponentUuid_whenUnknown_shouldReturnEmpty() { + assertThat(entityDao.selectByComponentUuid(db.getSession(), "unknown")).isEmpty(); + } + + @Test public void selectEntitiesByKeys_shouldReturnAllEntities() { ProjectData application = db.components().insertPrivateApplication(); ProjectData project = db.components().insertPrivateProject(); diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/measure/ProjectMeasuresIndexerIteratorIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/measure/ProjectMeasuresIndexerIteratorIT.java index a55affffc50..f8105bd490d 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/measure/ProjectMeasuresIndexerIteratorIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/measure/ProjectMeasuresIndexerIteratorIT.java @@ -166,17 +166,6 @@ public class ProjectMeasuresIndexerIteratorIT { } @Test - public void return_language_distribution_measure_from_project_with_no_branches() { - ComponentDto project = insertComponentAndProject(ComponentTesting.newPublicProjectDto(), false, - defaults(), defaults()); - - Map<String, ProjectMeasures> docsById = createResultSetAndReturnDocsById(); - - assertThat(docsById.get(project.uuid()).getMeasures().getNclocByLanguages()) - .isEmpty(); - } - - @Test public void does_not_return_none_numeric_metrics() { ComponentDto project = dbTester.components().insertPrivateProject().getMainBranchComponent(); MetricDto dataMetric = dbTester.measures().insertMetric(m -> m.setValueType(DATA.name()).setKey("data")); @@ -309,18 +298,4 @@ public class ProjectMeasuresIndexerIteratorIT { it.close(); return docsById; } - - private ComponentDto insertComponentAndProject(ComponentDto component, @Nullable Boolean isPrivate, - Consumer<ComponentDto> componentDtoPopulator, Consumer<ProjectDto> projectDtoPopulator) { - componentDtoPopulator.accept(component); - checkState(isPrivate == null || component.isPrivate() == isPrivate, "Illegal modification of private flag"); - dbClient.componentDao().insert(dbSession, component, true); - - ProjectDto projectDto = toProjectDto(component, System2.INSTANCE.now()); - projectDtoPopulator.accept(projectDto); - dbClient.projectDao().insert(dbSession, projectDto); - - dbTester.commit(); - return component; - } } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java index d1792b273b9..6430ec203c1 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java @@ -77,6 +77,13 @@ public class BranchDao implements Dao { return mapper(dbSession).selectByBranchKeys(branchKeyByProjectUuid); } + public List<BranchDto> selectByPullRequestKeys(DbSession dbSession, Map<String, String> prKeyByProjectUuid) { + if (prKeyByProjectUuid.isEmpty()) { + return emptyList(); + } + return mapper(dbSession).selectByPullRequestKeys(prKeyByProjectUuid); + } + public Optional<BranchDto> selectByPullRequestKey(DbSession dbSession, String projectUuid, String key) { return selectByKey(dbSession, projectUuid, key, BranchType.PULL_REQUEST); } @@ -115,7 +122,7 @@ public class BranchDao implements Dao { return mapper(dbSession).selectMainBranchByProjectUuid(projectUuid); } - public List<BranchDto> selectMainBranchesByProjectUuids(DbSession dbSession, Set<String> projectUuids) { + public List<BranchDto> selectMainBranchesByProjectUuids(DbSession dbSession, Collection<String> projectUuids) { if (projectUuids.isEmpty()) { return List.of(); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java index 4aa4b32281f..4e252fe19d4 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java @@ -48,6 +48,8 @@ public interface BranchMapper { List<BranchDto> selectByBranchKeys(@Param("branchKeyByProjectUuid") Map<String, String> branchKeyByProjectUuid); + List<BranchDto> selectByPullRequestKeys(@Param("prKeyByProjectUuid") Map<String, String> prKeyByProjectUuid); + List<BranchDto> selectByUuids(@Param("uuids") Collection<String> uuids); List<String> selectProjectUuidsWithIssuesNeedSync(@Param("projectUuids") Collection<String> uuids); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java index db97dd953c8..3774d62e061 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentDao.java @@ -228,12 +228,11 @@ public class ComponentDao implements Dao { * Used by Governance */ public Set<String> selectViewKeysWithEnabledCopyOfProject(DbSession session, Set<String> projectUuids) { - return executeLargeInputsIntoSet(projectUuids, - partition -> mapper(session).selectViewKeysWithEnabledCopyOfProject(partition), - i -> i); + return executeLargeInputsIntoSet(projectUuids, partition -> mapper(session).selectViewKeysWithEnabledCopyOfProject(partition), i -> i); } - public List<String> selectProjectsFromView(DbSession session, String viewUuid, String rootViewUuid) { + public List<String> selectProjectBranchUuidsFromView(DbSession session, String viewUuid, String rootViewUuid) { + // TODO why not query by scope/qualifier, using the view as the branchUuid? var escapedViewUuid = viewUuid.replace("_", "\\_").replace("%", "\\%"); return mapper(session).selectProjectsFromView("%." + escapedViewUuid + ".%", rootViewUuid); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java index d9d7c280dc7..f07753dc119 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentKeyUpdaterDao.java @@ -21,6 +21,7 @@ package org.sonar.db.component; import com.google.common.annotations.VisibleForTesting; import java.util.Collection; +import java.util.LinkedList; import java.util.List; import java.util.function.BiConsumer; import javax.annotation.Nullable; @@ -31,6 +32,7 @@ import org.sonar.db.Dao; import org.sonar.db.DbSession; import org.sonar.db.audit.AuditPersister; import org.sonar.db.audit.model.ComponentKeyNewValue; +import org.sonar.db.project.ProjectDto; /** * Class used to rename the key of a project and its resources. @@ -44,19 +46,15 @@ public class ComponentKeyUpdaterDao implements Dao { this.auditPersister = auditPersister; } - public void updateKey(DbSession dbSession, String projectUuid, String newKey) { + public void updateKey(DbSession dbSession, String projectUuid, String projectOldKey, String newKey) { ComponentKeyUpdaterMapper mapper = dbSession.getMapper(ComponentKeyUpdaterMapper.class); checkExistentKey(mapper, newKey); // must SELECT first everything - ResourceDto project = mapper.selectComponentByUuid(projectUuid); - String projectOldKey = project.getKey(); - List<ResourceDto> resources = mapper.selectBranchResources(projectUuid); - resources.add(project); + List<ResourceDto> resources = new LinkedList<>(); - // add branch components - dbSession.getMapper(BranchMapper.class).selectByProjectUuid(projectUuid).stream() - .filter(branch -> !projectUuid.equals(branch.getUuid())) + // add all branch components + dbSession.getMapper(BranchMapper.class).selectByProjectUuid(projectUuid) .forEach(branch -> { resources.addAll(mapper.selectBranchResources(branch.getUuid())); resources.add(mapper.selectComponentByUuid(branch.getUuid())); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/SnapshotDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/SnapshotDao.java index 9859d2370fa..11e5544e447 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/SnapshotDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/SnapshotDao.java @@ -69,11 +69,11 @@ public class SnapshotDao implements Dao { /** * returns the last analysis of any branch for each existing project */ - public List<ProjectLastAnalysisDateDto> selectLastAnalysisDateByProjects(DbSession session, Collection<String> projectUuids) { + public List<ProjectLastAnalysisDateDto> selectLastAnalysisDateByProjectUuids(DbSession session, Collection<String> projectUuids) { if (projectUuids.isEmpty()) { return Collections.emptyList(); } - return mapper(session).selectLastAnalysisDateByProjects(projectUuids); + return mapper(session).selectLastAnalysisDateByProjectUuids(projectUuids); } public Optional<SnapshotDto> selectLastAnalysisByRootComponentUuid(DbSession session, String componentUuid) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/SnapshotMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/SnapshotMapper.java index acf6105d11a..05186d5f7cf 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/SnapshotMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/SnapshotMapper.java @@ -38,7 +38,7 @@ public interface SnapshotMapper { @CheckForNull SnapshotDto selectLastSnapshotByRootComponentUuid(@Param("componentUuid") String componentUuid); - List<SnapshotDto> selectLastSnapshotsByRootComponentUuids(@Param("componentUuids") Collection<String> componentIds); + List<SnapshotDto> selectLastSnapshotsByRootComponentUuids(@Param("componentUuids") Collection<String> componentUuids); List<SnapshotDto> selectSnapshotsByQuery(@Param("query") SnapshotQuery query); @@ -57,5 +57,5 @@ public interface SnapshotMapper { @CheckForNull Long selectLastAnalysisDateByProject(String projectUuid); - List<ProjectLastAnalysisDateDto> selectLastAnalysisDateByProjects(@Param("projectUuids") Collection<String> projectUuids); + List<ProjectLastAnalysisDateDto> selectLastAnalysisDateByProjectUuids(@Param("projectUuids") Collection<String> projectUuids); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/UuidWithBranchUuidDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/UuidWithBranchUuidDto.java index 6f7a53b4560..33a4d75c5ad 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/UuidWithBranchUuidDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/UuidWithBranchUuidDto.java @@ -20,10 +20,13 @@ package org.sonar.db.component; public class UuidWithBranchUuidDto { - private String uuid; private String branchUuid; + /** + * branchUuid column in the components table for this component. + * It can be the UUID of a project or app branch, or the UUID of a portfolio. + */ public String getBranchUuid() { return branchUuid; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java index f0268ec9de5..d61cdcaf4fd 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDao.java @@ -54,6 +54,10 @@ public class EntityDao implements Dao { return executeLargeInputs(keys, partition -> mapper(dbSession).selectByKeys(partition)); } + public Optional<EntityDto> selectByComponentUuid(DbSession dbSession, String componentUuid) { + return Optional.ofNullable(mapper(dbSession).selectByComponentUuid(componentUuid)); + } + public void scrollForIndexing(DbSession session, @Nullable String entityUuid, ResultHandler<EntityDto> handler) { mapper(session).scrollForIndexing(entityUuid, handler); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java index 1ca0041731a..1131ef12ad4 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityMapper.java @@ -35,6 +35,9 @@ public interface EntityMapper { @CheckForNull EntityDto selectByKey(String key); + @CheckForNull + EntityDto selectByComponentUuid(String componentUuid); + List<EntityDto> selectByKeys(@Param("keys") Collection<String> keys); void scrollForIndexing(@Param("entityUuid") @Nullable String entityUuid, ResultHandler<EntityDto> handler); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java index 41307b39273..88b351b7126 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueDto.java @@ -214,6 +214,10 @@ public final class IssueDto implements Serializable { return this; } + /** + * The project branch where the issue is located. + * Note that the name is misleading - it should be branch. + */ public IssueDto setProject(ComponentDto project) { this.projectKey = project.getKey(); this.projectUuid = project.uuid(); @@ -572,6 +576,10 @@ public final class IssueDto implements Serializable { return this; } + /** + * The project branch where the issue is located. + * Note that the name is misleading - it should be 'branchUuid'. + */ public String getProjectUuid() { return projectUuid; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java index 4836b3969cb..338e0e41729 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java @@ -26,6 +26,7 @@ import org.sonar.api.resources.Qualifiers; import org.sonar.api.rule.Severity; import org.sonar.core.util.UuidFactoryFast; import org.sonar.core.util.Uuids; +import org.sonar.db.component.BranchDto; import org.sonar.db.component.ComponentDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.rule.RuleDto; @@ -48,8 +49,8 @@ public class IssueTesting { return newIssue(rule, branch.uuid(), branch.getKey(), file); } - public static IssueDto newIssue(RuleDto rule, ProjectDto project, ComponentDto file) { - return newIssue(rule, project.getUuid(), project.getKey(), file); + public static IssueDto newIssue(RuleDto rule, BranchDto branch, ComponentDto file) { + return newIssue(rule, branch.getUuid(), branch.getKey(), file); } public static IssueDto newIssue(RuleDto rule, String branchUuid, String projectKey, ComponentDto file) { @@ -80,7 +81,7 @@ public class IssueTesting { .setUpdatedAt(System.currentTimeMillis() - 500); } - public static IssueChangeDto newIssuechangeDto(IssueDto issue) { + public static IssueChangeDto newIssueChangeDto(IssueDto issue) { return new IssueChangeDto() .setUuid(UuidFactoryFast.getInstance().create()) .setKey(UuidFactoryFast.getInstance().create()) diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/ProjectMeasuresIndexerIterator.java b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/ProjectMeasuresIndexerIterator.java index 99e57c6a50d..5cc3ea168a5 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/measure/ProjectMeasuresIndexerIterator.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/measure/ProjectMeasuresIndexerIterator.java @@ -72,38 +72,47 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea CoreMetrics.NEW_LINES_KEY, CoreMetrics.NEW_RELIABILITY_RATING_KEY); - private static final String SQL_PROJECTS = "SELECT p.uuid, p.kee, p.name, s.created_at, p.tags, p.qualifier " + - "FROM projects p " + - "LEFT OUTER JOIN snapshots s ON s.component_uuid=p.uuid AND s.islast=? " + - "WHERE p.qualifier in (?, ?)"; - - private static final String PROJECT_FILTER = " AND p.uuid=?"; - - private static final String SQL_MEASURES = "SELECT m.name, pm.value, pm.text_value FROM live_measures pm " + - "INNER JOIN metrics m ON m.uuid = pm.metric_uuid " + - "WHERE pm.component_uuid = ? " + - "AND m.name IN ({metricNames}) " + - "AND (pm.value IS NOT NULL OR pm.text_value IS NOT NULL) " + - "AND m.enabled = ? "; - - private static final String SQL_NCLOC_LANGUAGE_DISTRIBUTION = "SELECT m.name, pm.value, pm.text_value FROM live_measures pm " + - "INNER JOIN metrics m ON m.uuid = pm.metric_uuid " + - "WHERE pm.component_uuid = ? " + - "AND m.name = ? " + - "AND (pm.value IS NOT NULL OR pm.text_value IS NOT NULL) " + - "AND m.enabled = ? "; - - private static final String SQL_BIGGEST_NCLOC_VALUE = "SELECT max(lm.value) FROM metrics m " + - "INNER JOIN live_measures lm ON m.uuid = lm.metric_uuid " + - "INNER JOIN project_branches pb ON lm.component_uuid = pb.uuid " + - "WHERE pb.project_uuid = ? " + - "AND m.name = ? AND lm.value IS NOT NULL AND m.enabled = ? "; - - private static final String SQL_BRANCH_BY_NCLOC = "SELECT lm.component_uuid FROM metrics m " + - "INNER JOIN live_measures lm ON m.uuid = lm.metric_uuid " + - "INNER JOIN project_branches pb ON lm.component_uuid = pb.uuid " + - "WHERE pb.project_uuid = ? " + - "AND m.name = ? AND lm.value = ? AND m.enabled = ? "; + private static final String SQL_PROJECTS = """ + SELECT p.uuid, p.kee, p.name, s.created_at, p.tags, p.qualifier + FROM projects p + INNER JOIN project_branches pb on p.uuid = pb.project_uuid + LEFT OUTER JOIN snapshots s ON s.component_uuid=pb.uuid AND s.islast=? + WHERE pb.is_main = ? + AND p.qualifier in (?, ?)"""; + + private static final String PROJECT_FILTER = " AND pb.project_uuid=?"; + + private static final String SQL_MEASURES = """ + SELECT m.name, pm.value, pm.text_value FROM live_measures pm + INNER JOIN metrics m ON m.uuid = pm.metric_uuid + INNER JOIN project_branches pb ON pb.uuid = pm.component_uuid + WHERE pb.project_uuid = ? + AND pb.is_main = ? + AND m.name IN ({metricNames}) + AND (pm.value IS NOT NULL OR pm.text_value IS NOT NULL) + AND m.enabled = ?"""; + + private static final String SQL_NCLOC_LANGUAGE_DISTRIBUTION = """ + SELECT m.name, pm.value, pm.text_value FROM live_measures pm + INNER JOIN metrics m ON m.uuid = pm.metric_uuid + WHERE pm.component_uuid = ? + AND m.name = ? + AND (pm.value IS NOT NULL OR pm.text_value IS NOT NULL) + AND m.enabled = ?"""; + + private static final String SQL_BIGGEST_NCLOC_VALUE = """ + SELECT max(lm.value) FROM metrics m + INNER JOIN live_measures lm ON m.uuid = lm.metric_uuid + INNER JOIN project_branches pb ON lm.component_uuid = pb.uuid + WHERE pb.project_uuid = ? + AND m.name = ? AND lm.value IS NOT NULL AND m.enabled = ? """; + + private static final String SQL_BRANCH_BY_NCLOC = """ + SELECT lm.component_uuid FROM metrics m + INNER JOIN live_measures lm ON m.uuid = lm.metric_uuid + INNER JOIN project_branches pb ON lm.component_uuid = pb.uuid + WHERE pb.project_uuid = ? + AND m.name = ? AND lm.value = ? AND m.enabled = ?"""; private static final boolean ENABLED = true; private static final int FIELD_METRIC_NAME = 1; @@ -129,7 +138,7 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea private static List<Project> selectProjects(DbSession session, @Nullable String projectUuid) { List<Project> projects = new ArrayList<>(); try (PreparedStatement stmt = createProjectsStatement(session, projectUuid); - ResultSet rs = stmt.executeQuery()) { + ResultSet rs = stmt.executeQuery()) { while (rs.next()) { String uuid = rs.getString(1); String key = rs.getString(2); @@ -154,10 +163,11 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea } PreparedStatement stmt = session.getConnection().prepareStatement(sql.toString()); stmt.setBoolean(1, true); - stmt.setString(2, Qualifiers.PROJECT); - stmt.setString(3, Qualifiers.APP); + stmt.setBoolean(2, true); + stmt.setString(3, Qualifiers.PROJECT); + stmt.setString(4, Qualifiers.APP); if (projectUuid != null) { - stmt.setString(4, projectUuid); + stmt.setString(5, projectUuid); } return stmt; } catch (SQLException e) { @@ -219,6 +229,7 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea private void prepareMeasuresStatement(String projectUuid) throws SQLException { AtomicInteger index = new AtomicInteger(1); measuresStatement.setString(index.getAndIncrement(), projectUuid); + measuresStatement.setBoolean(index.getAndIncrement(), true); METRIC_KEYS .stream() .filter(m -> !m.equals(NCLOC_LANGUAGE_DISTRIBUTION_KEY)) @@ -226,11 +237,11 @@ public class ProjectMeasuresIndexerIterator extends CloseableIterator<ProjectMea measuresStatement.setBoolean(index.getAndIncrement(), ENABLED); } - private static PreparedStatement prepareNclocByLanguageStatement(DbSession session, String projectUuid) { + private static PreparedStatement prepareNclocByLanguageStatement(DbSession session, String branchUuid) { try { PreparedStatement stmt = session.getConnection().prepareStatement(SQL_NCLOC_LANGUAGE_DISTRIBUTION); AtomicInteger index = new AtomicInteger(1); - stmt.setString(index.getAndIncrement(), projectUuid); + stmt.setString(index.getAndIncrement(), branchUuid); stmt.setString(index.getAndIncrement(), NCLOC_LANGUAGE_DISTRIBUTION_KEY); stmt.setBoolean(index.getAndIncrement(), ENABLED); return stmt; 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 47471258409..73f030a9d6b 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 @@ -19,6 +19,7 @@ */ package org.sonar.db.project; +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; @@ -69,7 +70,7 @@ public class ProjectDao implements Dao { return mapper(session).selectAllApplications(); } - public List<ProjectDto> selectProjectsByKeys(DbSession session, Set<String> keys) { + public List<ProjectDto> selectProjectsByKeys(DbSession session, Collection<String> keys) { if (keys.isEmpty()) { return emptyList(); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml index 78da4219aef..6e056b19b64 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml @@ -107,8 +107,21 @@ <foreach collection="branchKeyByProjectUuid" index="key" item="value" open="" separator=" or " close=""> (pb.project_uuid=#{key,jdbcType=VARCHAR} and pb.kee=#{value,jdbcType=VARCHAR}) </foreach> + and pb.branch_type='BRANCH' </select> + <select id="selectByPullRequestKeys" resultType="org.sonar.db.component.BranchDto"> + select + <include refid="columns"/> + from project_branches pb + where + <foreach collection="prKeyByProjectUuid" index="key" item="value" open="" separator=" or " close=""> + (pb.project_uuid=#{key,jdbcType=VARCHAR} and pb.kee=#{value,jdbcType=VARCHAR}) + </foreach> + and pb.branch_type='PULL_REQUEST' + </select> + + <select id="selectBranchMeasuresWithCaycMetric" resultType="org.sonar.db.component.BranchMeasuresDto"> select <include refid="telemetryColumns"/> diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/SnapshotMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/SnapshotMapper.xml index da7a40f453d..746a1efd27f 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/SnapshotMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/SnapshotMapper.xml @@ -54,7 +54,7 @@ and coalesce(pb.project_uuid, p.branch_uuid) = #{projectUuid,jdbcType=VARCHAR} </select> - <select id="selectLastAnalysisDateByProjects" resultType="org.sonar.db.component.ProjectLastAnalysisDateDto"> + <select id="selectLastAnalysisDateByProjectUuids" resultType="org.sonar.db.component.ProjectLastAnalysisDateDto"> select result_with_duplicates.project_uuid as project_uuid , max(result_with_duplicates.last_analysis_date) as last_analysis_date @@ -70,14 +70,14 @@ where s.islast = ${_true} and ( - <!-- case of an analysis of a project or app, with entries in project_branches --> - (pb.uuid is not null and pb.project_uuid in + <!-- case of an analysis of a project or app, with entries in project_branches --> + (pb.uuid is not null and pb.project_uuid in <foreach collection="projectUuids" item="projectUuid" separator="," open="(" close=")"> #{projectUuid,jdbcType=VARCHAR} </foreach>) or - <!-- case of an analysis of a portfolio, where there are no branches --> - (pb.uuid is null and c.branch_uuid in + <!-- case of an analysis of a portfolio, where there are no branches --> + (pb.uuid is null and c.branch_uuid in <foreach collection="projectUuids" item="projectUuid" separator="," open="(" close=")"> #{projectUuid,jdbcType=VARCHAR} </foreach>) @@ -86,7 +86,6 @@ group by result_with_duplicates.project_uuid </select> - <select id="selectLastSnapshotByRootComponentUuid" resultType="Snapshot"> select <include refid="snapshotColumns" /> from snapshots s @@ -102,7 +101,7 @@ <foreach collection="componentUuids" item="componentUuid" separator="," open="(" close=")"> #{componentUuid,jdbcType=VARCHAR} </foreach> - </select> + </select> <select id="selectSnapshotsByQuery" parameterType="map" resultType="Snapshot"> SELECT diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml index 5e071421ae0..5b04f607600 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/entity/EntityMapper.xml @@ -22,7 +22,20 @@ where p.uuid = #{uuid,jdbcType=VARCHAR}) </select> - <sql id="selectAll"> + <select id="selectByComponentUuid" parameterType="string" resultType="Entity"> + (select <include refid="entityProjectColumns"/> + from projects p + inner join project_branches pb on pb.project_uuid = p.uuid + inner join components c on c.branch_uuid = pb.uuid + where c.uuid = #{uuid,jdbcType=VARCHAR}) + UNION + (select <include refid="entityPortfolioColumns"/> + from portfolios p + inner join components c on c.branch_uuid = p.uuid + where c.uuid = #{uuid,jdbcType=VARCHAR}) + </select> + + <sql id="selectAll"> (select <include refid="org.sonar.db.entity.EntityMapper.entityProjectColumns"/> from projects p) UNION diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentDbTester.java index ff87690d1c3..9cbe6155a8c 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentDbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentDbTester.java @@ -93,7 +93,8 @@ public class ComponentDbTester { } public ComponentDto getComponentDto(ProjectDto project) { - return db.getDbClient().componentDao().selectByUuid(dbSession, project.getUuid()) + BranchDto branchDto = db.getDbClient().branchDao().selectMainBranchByProjectUuid(dbSession, project.getUuid()).get(); + return db.getDbClient().componentDao().selectByUuid(dbSession, branchDto.getUuid()) .orElseThrow(() -> new IllegalStateException("Can't find project")); } diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/issue/IssueDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/issue/IssueDbTester.java index 96fdfcb5df9..f207b8e00da 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/issue/IssueDbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/issue/IssueDbTester.java @@ -29,9 +29,9 @@ import org.sonar.core.issue.DefaultIssueComment; import org.sonar.core.issue.FieldDiffs; import org.sonar.core.util.Uuids; 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.project.ProjectDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.user.UserDto; @@ -101,8 +101,8 @@ public class IssueDbTester { } @SafeVarargs - public final IssueDto insert(RuleDto rule, ProjectDto project, ComponentDto file, Consumer<IssueDto>... populators) { - IssueDto issue = newIssue(rule, project, file); + public final IssueDto insert(RuleDto rule, BranchDto branch, ComponentDto file, Consumer<IssueDto>... populators) { + IssueDto issue = newIssue(rule, branch, file); stream(populators).forEach(p -> p.accept(issue)); return insert(issue); } @@ -180,9 +180,9 @@ public class IssueDbTester { return insertHotspot(rule, project.getMainBranchComponent(), file, populators); } - public final IssueDto insertHotspot(ProjectDto project, ComponentDto file, Consumer<IssueDto>... populators) { + public final IssueDto insertHotspot(BranchDto branchDto, ComponentDto file, Consumer<IssueDto>... populators) { RuleDto rule = db.rules().insertHotspotRule(); - IssueDto issue = newIssue(rule, project, file) + IssueDto issue = newIssue(rule, branchDto, file) .setType(SECURITY_HOTSPOT) .setStatus(Issue.STATUS_TO_REVIEW) .setResolution(null); @@ -220,7 +220,7 @@ public class IssueDbTester { @SafeVarargs public final IssueChangeDto insertChange(IssueDto issueDto, Consumer<IssueChangeDto>... populators) { - IssueChangeDto dto = IssueTesting.newIssuechangeDto(issueDto); + IssueChangeDto dto = IssueTesting.newIssueChangeDto(issueDto); stream(populators).forEach(p -> p.accept(dto)); return insertChange(dto); } |