From 93734208da4519e1872e80c59f7edd1612dac5da Mon Sep 17 00:00:00 2001 From: Lukasz Jarocki Date: Thu, 15 Jun 2023 10:45:35 +0200 Subject: [PATCH] SONAR-19556 org.sonar.server.project.Project#from(org.sonar.db.component.ComponentDto) should not be used in production --- .../LoadReportAnalysisMetadataHolderStep.java | 2 +- .../java/org/sonar/db/entity/EntityDaoIT.java | 11 ++++++++- .../java/org/sonar/db/entity/EntityDto.java | 8 +++++++ .../org/sonar/db/portfolio/PortfolioDto.java | 6 ----- .../java/org/sonar/db/project/ProjectDto.java | 6 ----- .../org/sonar/db/entity/EntityMapper.xml | 5 ++-- .../org/sonar/server/project/Project.java | 8 +++---- .../org/sonar/server/project/ProjectTest.java | 24 +++++++++++++++++++ .../server/branch/ws/DeleteActionIT.java | 2 +- .../sonar/server/branch/ws/DeleteAction.java | 3 ++- .../server/project/ws/BulkDeleteAction.java | 5 +++- .../sonar/server/project/ws/DeleteAction.java | 3 ++- 12 files changed, 59 insertions(+), 24 deletions(-) diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java index cf22eac9e87..14ad8283eaa 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadReportAnalysisMetadataHolderStep.java @@ -100,7 +100,7 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { } ProjectDto dto = toProject(reportMetadata.getProjectKey()); - analysisMetadata.setProject(Project.from(dto)); + analysisMetadata.setProject(Project.fromProjectDtoWithTags(dto)); return () -> { if (!mainComponentKey.equals(reportMetadata.getProjectKey())) { throw MessageException.of(format( 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 7c21aa67ce5..7b54d98409c 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 @@ -37,7 +37,7 @@ public class EntityDaoIT { private final System2 system2 = new AlwaysIncreasingSystem2(1000L); @Rule - public DbTester db = DbTester.create(system2); + public DbTester db = DbTester.create(system2, true); private final EntityDao entityDao = new EntityDao(); @@ -84,6 +84,15 @@ public class EntityDaoIT { assertThat(entityDao.selectByUuid(db.getSession(), portfolio.getUuid()).get().getKey()).isEqualTo(portfolio.getKey()); } + @Test + public void getDescription_shouldNotReturnNull() { + ProjectData project = db.components().insertPrivateProject(); + PortfolioDto portfolio = db.components().insertPrivatePortfolioDto(); + + assertThat(entityDao.selectByUuid(db.getSession(), project.projectUuid()).get().getDescription()).isNotNull(); + assertThat(entityDao.selectByUuid(db.getSession(), portfolio.getUuid()).get().getDescription()).isNotNull(); + } + @Test public void selectEntityByUuid_whenNoMatch_shouldReturnEmpty() { assertThat(entityDao.selectByUuid(db.getSession(), "unknown")).isEmpty(); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDto.java index 15c4b85ef0f..39932908c59 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/entity/EntityDto.java @@ -20,6 +20,7 @@ package org.sonar.db.entity; import java.util.Objects; +import javax.annotation.CheckForNull; import org.sonar.api.resources.Qualifiers; /** @@ -27,10 +28,12 @@ import org.sonar.api.resources.Qualifiers; * Entities are stored either in the projects or portfolios tables. */ public class EntityDto { + protected String kee; protected String uuid; protected String name; protected String qualifier; + protected String description; protected boolean isPrivate; // This field should be null for anything that is not subportfolio @@ -66,6 +69,11 @@ public class EntityDto { return name; } + @CheckForNull + public String getDescription() { + return description; + } + public boolean isPrivate() { return isPrivate; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java index d5f63653f26..50df9b0895e 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java @@ -29,7 +29,6 @@ public class PortfolioDto extends EntityDto { NONE, MANUAL, REGEXP, REST, TAGS } - private String description; private String branchKey; private String rootUuid; @@ -149,11 +148,6 @@ public class PortfolioDto extends EntityDto { return this; } - @CheckForNull - public String getDescription() { - return description; - } - public PortfolioDto setDescription(@Nullable String description) { this.description = description; return this; diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDto.java index 6e48cccde0c..81190a9f61a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/project/ProjectDto.java @@ -30,7 +30,6 @@ import static org.sonar.db.component.DbTagsReader.readDbTags; public class ProjectDto extends EntityDto { private static final String TAGS_SEPARATOR = ","; - private String description; private String tags; private long createdAt; private long updatedAt; @@ -104,11 +103,6 @@ public class ProjectDto extends EntityDto { return this; } - @CheckForNull - public String getDescription() { - return description; - } - public ProjectDto setDescription(@Nullable String description) { this.description = description; return this; 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 3f3780008a4..5e071421ae0 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 @@ -2,11 +2,12 @@ - p.uuid as uuid, p.kee as kee, p.name as name, p.private as isPrivate, p.qualifier as qualifier, null as authUuid + p.uuid as uuid, p.kee as kee, p.name as name, p.private as isPrivate, p.description as description, p.qualifier as qualifier, + null as authUuid - p.uuid as uuid, p.kee as kee, p.name as name, p.private as isPrivate, + p.uuid as uuid, p.kee as kee, p.name as name, p.private as isPrivate, p.description as description, case when p.parent_uuid is null then 'VW' else 'SVW' end as qualifier, case when p.root_uuid != p.uuid then p.root_uuid else null end as authUuid diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/project/Project.java b/server/sonar-server-common/src/main/java/org/sonar/server/project/Project.java index f09b33178ac..65137bdd543 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/project/Project.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/project/Project.java @@ -24,7 +24,7 @@ import java.util.Objects; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import org.sonar.db.component.ComponentDto; -import org.sonar.db.portfolio.PortfolioDto; +import org.sonar.db.entity.EntityDto; import org.sonar.db.project.ProjectDto; import static java.util.Collections.emptyList; @@ -50,12 +50,12 @@ public class Project { return new Project(project.uuid(), project.getKey(), project.name(), project.description(), emptyList()); } - public static Project from(ProjectDto project) { + public static Project fromProjectDtoWithTags(ProjectDto project) { return new Project(project.getUuid(), project.getKey(), project.getName(), project.getDescription(), project.getTags()); } - public static Project from(PortfolioDto portfolio) { - return new Project(portfolio.getUuid(), portfolio.getKey(), portfolio.getName(), portfolio.getDescription(), emptyList()); + public static Project from(EntityDto entityDto) { + return new Project(entityDto.getUuid(), entityDto.getKey(), entityDto.getName(), entityDto.getDescription(), emptyList()); } /** diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/project/ProjectTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/project/ProjectTest.java index 8084227d04b..9ff5ccf46d8 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/project/ProjectTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/project/ProjectTest.java @@ -20,9 +20,12 @@ package org.sonar.server.project; import org.junit.Test; +import org.sonar.db.entity.EntityDto; import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class ProjectTest { @Test @@ -54,6 +57,27 @@ public class ProjectTest { .isEqualTo("Project{uuid='U1', key='K1', name='N1', description='D1'}"); } + @Test + public void from_whenPortfolioPassed_shouldNotReturnNullFields() { + EntityDto entity = mock(EntityDto.class); + + when(entity.getUuid()).thenReturn("U1"); + when(entity.getKey()).thenReturn("K1"); + when(entity.getName()).thenReturn("N1"); + when(entity.getDescription()).thenReturn("D1"); + + Project underTest = Project.from(entity); + + assertThat(underTest.getUuid()).isEqualTo("U1"); + assertThat(underTest.getKey()).isEqualTo("K1"); + assertThat(underTest.getName()).isEqualTo("N1"); + assertThat(underTest.getDescription()).isEqualTo("D1"); + + assertThat(underTest.toString()) + .isEqualTo(underTest.toString()) + .isEqualTo("Project{uuid='U1', key='K1', name='N1', description='D1'}"); + } + @Test public void test_equals_and_hashCode() { Project project1 = new Project("U1", "K1", "N1", null, emptyList()); diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java index d6878af3c68..14a64e315ec 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/branch/ws/DeleteActionIT.java @@ -72,7 +72,7 @@ public class DeleteActionIT { .execute(); verifyDeletedKey("branch1"); - verify(projectLifeCycleListeners).onProjectBranchesDeleted(singleton(Project.from(project))); + verify(projectLifeCycleListeners).onProjectBranchesDeleted(singleton(Project.fromProjectDtoWithTags(project))); } @Test diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/DeleteAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/DeleteAction.java index ce191851607..aac84f6ad7c 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/DeleteAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/DeleteAction.java @@ -30,6 +30,7 @@ import org.sonar.db.component.BranchDto; import org.sonar.db.project.ProjectDto; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.project.Project; import org.sonar.server.project.ProjectLifeCycleListeners; import org.sonar.server.user.UserSession; @@ -89,7 +90,7 @@ public class DeleteAction implements BranchWsAction { throw new IllegalArgumentException("Only non-main branches can be deleted"); } componentCleanerService.deleteBranch(dbSession, branch); - projectLifeCycleListeners.onProjectBranchesDeleted(singleton(from(project))); + projectLifeCycleListeners.onProjectBranchesDeleted(singleton(Project.fromProjectDtoWithTags(project))); response.noContent(); } } 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 a38add5920c..d19c97b8dd8 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 @@ -39,6 +39,7 @@ 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.entity.EntityDto; import org.sonar.db.permission.GlobalPermission; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.project.Project; @@ -49,6 +50,7 @@ import org.sonar.server.user.UserSession; import static com.google.common.base.Preconditions.checkArgument; import static java.lang.Math.min; import static java.lang.String.format; +import static java.util.stream.Collectors.toSet; import static org.sonar.api.resources.Qualifiers.APP; import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.api.resources.Qualifiers.VIEW; @@ -146,11 +148,12 @@ public class BulkDeleteAction implements ProjectsWsAction { ComponentQuery query = buildDbQuery(searchRequest); Set componentDtos = new HashSet<>(dbClient.componentDao().selectByQuery(dbSession, query, 0, Integer.MAX_VALUE)); + List entities = dbClient.entityDao().selectByKeys(dbSession, componentDtos.stream().map(ComponentDto::getKey).collect(toSet())); try { componentDtos.forEach(p -> componentCleanerService.deleteComponent(dbSession, p)); } finally { - projectLifeCycleListeners.onProjectsDeleted(componentDtos.stream().map(Project::from).collect(MoreCollectors.toSet(componentDtos.size()))); + projectLifeCycleListeners.onProjectsDeleted(entities.stream().map(Project::from).collect(MoreCollectors.toSet(componentDtos.size()))); } } response.noContent(); 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 0f08cd62a47..0417946b832 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 @@ -29,6 +29,7 @@ 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.Project; import org.sonar.server.project.ProjectLifeCycleListeners; import org.sonar.server.user.UserSession; @@ -82,7 +83,7 @@ public class DeleteAction implements ProjectsWsAction { ProjectDto project = componentFinder.getProjectByKey(dbSession, key); checkPermission(project); componentCleanerService.delete(dbSession, project); - projectLifeCycleListeners.onProjectsDeleted(singleton(from(project))); + projectLifeCycleListeners.onProjectsDeleted(singleton(Project.fromProjectDtoWithTags(project))); } response.noContent(); -- 2.39.5