From 01f2c2e66d698a60ad1f303cf7aafaf64852e7a8 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Wed, 16 Jan 2019 15:37:00 +0100 Subject: [PATCH] SONAR-11439 Analysis of long branch doesn't trigger purge of dependent short branches and pull requests --- .../projectanalysis/purge/ProjectCleaner.java | 7 ++- .../purge/PurgeDatastoresStep.java | 15 +++--- .../DuplicationRepositoryImplTest.java | 11 ++-- .../projectanalysis/measure/MeasureTest.java | 10 ++-- .../purge/ProjectCleanerTest.java | 7 ++- .../purge/PurgeDatastoresStepTest.java | 52 ++++++++----------- .../sonar/db/purge/PurgeConfiguration.java | 28 +++++++--- .../java/org/sonar/db/purge/PurgeDao.java | 14 ++--- .../java/org/sonar/db/purge/PurgeMapper.java | 2 +- .../org/sonar/db/purge/PurgeMapper.xml | 2 +- .../db/purge/PurgeConfigurationTest.java | 12 ++--- .../java/org/sonar/db/purge/PurgeDaoTest.java | 48 +++++++++++++---- .../server/util/WrapInSingleElementArray.java | 4 +- 13 files changed, 121 insertions(+), 91 deletions(-) diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleaner.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleaner.java index a4cb50ba69f..6d462db18a0 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleaner.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleaner.java @@ -28,7 +28,6 @@ import org.sonar.api.utils.TimeUtils; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.db.DbSession; -import org.sonar.db.purge.IdUuidPair; import org.sonar.db.purge.PurgeConfiguration; import org.sonar.db.purge.PurgeDao; import org.sonar.db.purge.PurgeListener; @@ -54,13 +53,13 @@ public class ProjectCleaner { this.purgeListener = purgeListener; } - public ProjectCleaner purge(DbSession session, IdUuidPair rootId, Configuration projectConfig, Collection disabledComponentUuids) { + public ProjectCleaner purge(DbSession session, String rootUuid, String projectUuid, Configuration projectConfig, Collection disabledComponentUuids) { long start = System.currentTimeMillis(); profiler.reset(); - PurgeConfiguration configuration = newDefaultPurgeConfiguration(projectConfig, rootId, disabledComponentUuids); + periodCleaner.clean(session, rootUuid, projectConfig); - periodCleaner.clean(session, configuration.rootProjectIdUuid().getUuid(), projectConfig); + PurgeConfiguration configuration = newDefaultPurgeConfiguration(projectConfig, rootUuid, projectUuid, disabledComponentUuids); purgeDao.purge(session, configuration, purgeListener, profiler); session.commit(); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/PurgeDatastoresStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/PurgeDatastoresStep.java index 50b7d9e0557..1c863e86c73 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/PurgeDatastoresStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/PurgeDatastoresStep.java @@ -19,9 +19,9 @@ */ package org.sonar.ce.task.projectanalysis.purge; +import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; import org.sonar.ce.task.projectanalysis.component.Component; import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository; -import org.sonar.ce.task.projectanalysis.component.DbIdsRepository; import org.sonar.ce.task.projectanalysis.component.DepthTraversalTypeAwareCrawler; import org.sonar.ce.task.projectanalysis.component.DisabledComponentsHolder; import org.sonar.ce.task.projectanalysis.component.TreeRootHolder; @@ -29,7 +29,6 @@ import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter; import org.sonar.ce.task.step.ComputationStep; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.purge.IdUuidPair; import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT; import static org.sonar.ce.task.projectanalysis.component.Component.Type.VIEW; @@ -40,19 +39,19 @@ public class PurgeDatastoresStep implements ComputationStep { private final ProjectCleaner projectCleaner; private final DbClient dbClient; - private final DbIdsRepository dbIdsRepository; private final TreeRootHolder treeRootHolder; private final ConfigurationRepository configRepository; private final DisabledComponentsHolder disabledComponentsHolder; + private final AnalysisMetadataHolder analysisMetadataHolder; - public PurgeDatastoresStep(DbClient dbClient, ProjectCleaner projectCleaner, DbIdsRepository dbIdsRepository, TreeRootHolder treeRootHolder, - ConfigurationRepository configRepository, DisabledComponentsHolder disabledComponentsHolder) { + public PurgeDatastoresStep(DbClient dbClient, ProjectCleaner projectCleaner, TreeRootHolder treeRootHolder, + ConfigurationRepository configRepository, DisabledComponentsHolder disabledComponentsHolder, AnalysisMetadataHolder analysisMetadataHolder) { this.projectCleaner = projectCleaner; this.dbClient = dbClient; - this.dbIdsRepository = dbIdsRepository; this.treeRootHolder = treeRootHolder; this.configRepository = configRepository; this.disabledComponentsHolder = disabledComponentsHolder; + this.analysisMetadataHolder = analysisMetadataHolder; } @Override @@ -73,8 +72,8 @@ public class PurgeDatastoresStep implements ComputationStep { private void execute(Component root) { try (DbSession dbSession = dbClient.openSession(true)) { - IdUuidPair idUuidPair = new IdUuidPair(dbIdsRepository.getComponentId(root), root.getUuid()); - projectCleaner.purge(dbSession, idUuidPair, configRepository.getConfiguration(), disabledComponentsHolder.getUuids()); + String projectUuid = analysisMetadataHolder.getProject().getUuid(); + projectCleaner.purge(dbSession, root.getUuid(), projectUuid, configRepository.getConfiguration(), disabledComponentsHolder.getUuids()); dbSession.commit(); } } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/duplication/DuplicationRepositoryImplTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/duplication/DuplicationRepositoryImplTest.java index 51388afcfe5..a30d1acf4ef 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/duplication/DuplicationRepositoryImplTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/duplication/DuplicationRepositoryImplTest.java @@ -32,9 +32,6 @@ import org.sonar.ce.task.projectanalysis.component.Component; import org.sonar.ce.task.projectanalysis.component.ReportComponent; import org.sonar.server.util.WrapInSingleElementArray; -import static com.google.common.base.Predicates.equalTo; -import static com.google.common.base.Predicates.not; -import static com.google.common.collect.FluentIterable.from; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -138,10 +135,10 @@ public class DuplicationRepositoryImplTest { @DataProvider public static Object[][] allComponentTypesButFile() { - return from(Arrays.asList(Component.Type.values())) - .filter(not(equalTo(Component.Type.FILE))) - .transform(WrapInSingleElementArray.INSTANCE) - .toArray(Object[].class); + return Arrays.stream(Component.Type.values()) + .filter(t -> t != Component.Type.FILE) + .map(WrapInSingleElementArray.INSTANCE) + .toArray(Object[][]::new); } private void assertNoDuplication(Component component) { diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureTest.java index 4351d5e40c7..d3f2695f108 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/MeasureTest.java @@ -33,7 +33,6 @@ import org.sonar.ce.task.projectanalysis.component.DumbDeveloper; import org.sonar.ce.task.projectanalysis.measure.Measure.ValueType; import org.sonar.server.util.WrapInSingleElementArray; -import static com.google.common.collect.FluentIterable.from; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder; @@ -88,13 +87,14 @@ public class MeasureTest { @DataProvider public static Object[][] all() { - return from(MEASURES).transform(WrapInSingleElementArray.INSTANCE).toArray(Object[].class); + return MEASURES.stream().map(WrapInSingleElementArray.INSTANCE).toArray(Object[][]::new); } private static Object[][] getMeasuresExcept(final ValueType valueType) { - return from(MEASURES) - .filter(input -> input.getValueType() != valueType).transform(WrapInSingleElementArray.INSTANCE) - .toArray(Object[].class); + return MEASURES.stream() + .filter(input -> input.getValueType() != valueType) + .map(WrapInSingleElementArray.INSTANCE) + .toArray(Object[][]::new); } @Test diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java index 78262afa632..f5fd0dabdd0 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/ProjectCleanerTest.java @@ -27,7 +27,6 @@ import org.sonar.api.config.internal.MapSettings; import org.sonar.core.config.PurgeConstants; import org.sonar.core.config.PurgeProperties; import org.sonar.db.DbSession; -import org.sonar.db.purge.IdUuidPair; import org.sonar.db.purge.PurgeDao; import org.sonar.db.purge.PurgeListener; import org.sonar.db.purge.PurgeProfiler; @@ -58,7 +57,7 @@ public class ProjectCleanerTest { public void no_profiling_when_property_is_false() { settings.setProperty(CoreProperties.PROFILING_LOG_PROPERTY, false); - underTest.purge(mock(DbSession.class), mock(IdUuidPair.class), settings.asConfig(), emptyList()); + underTest.purge(mock(DbSession.class), "root", "project", settings.asConfig(), emptyList()); verify(profiler, never()).dump(anyLong(), any()); } @@ -67,7 +66,7 @@ public class ProjectCleanerTest { public void profiling_when_property_is_true() { settings.setProperty(CoreProperties.PROFILING_LOG_PROPERTY, true); - underTest.purge(mock(DbSession.class), mock(IdUuidPair.class), settings.asConfig(), emptyList()); + underTest.purge(mock(DbSession.class), "root", "project", settings.asConfig(), emptyList()); verify(profiler).dump(anyLong(), any()); } @@ -76,7 +75,7 @@ public class ProjectCleanerTest { public void call_period_cleaner_index_client_and_purge_dao() { settings.setProperty(PurgeConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES, 5); - underTest.purge(mock(DbSession.class), mock(IdUuidPair.class), settings.asConfig(), emptyList()); + underTest.purge(mock(DbSession.class), "root", "project", settings.asConfig(), emptyList()); verify(periodCleaner).clean(any(), any(), any()); verify(dao).purge(any(), any(), any(), any()); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/PurgeDatastoresStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/PurgeDatastoresStepTest.java index e71d6ea6de4..dbf8227eaee 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/PurgeDatastoresStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/PurgeDatastoresStepTest.java @@ -19,20 +19,22 @@ */ package org.sonar.ce.task.projectanalysis.purge; -import com.google.common.base.Predicate; -import com.google.common.collect.FluentIterable; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.Arrays; +import java.util.Collections; +import java.util.function.Predicate; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.sonar.api.config.internal.MapSettings; +import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule; import org.sonar.ce.task.projectanalysis.component.Component; import org.sonar.ce.task.projectanalysis.component.ConfigurationRepository; -import org.sonar.ce.task.projectanalysis.component.MutableDbIdsRepositoryRule; import org.sonar.ce.task.projectanalysis.component.MutableDisabledComponentsHolder; import org.sonar.ce.task.projectanalysis.component.ReportComponent; import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule; @@ -41,12 +43,12 @@ import org.sonar.ce.task.projectanalysis.step.BaseStepTest; import org.sonar.ce.task.step.ComputationStep; import org.sonar.ce.task.step.TestComputationStepContext; import org.sonar.db.DbClient; -import org.sonar.db.purge.IdUuidPair; +import org.sonar.server.project.Project; import org.sonar.server.util.WrapInSingleElementArray; -import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -57,20 +59,24 @@ import static org.mockito.Mockito.when; public class PurgeDatastoresStepTest extends BaseStepTest { private static final String PROJECT_KEY = "PROJECT_KEY"; - private static final long PROJECT_ID = 123L; private static final String PROJECT_UUID = "UUID-1234"; @Rule public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); @Rule - public MutableDbIdsRepositoryRule dbIdsRepository = MutableDbIdsRepositoryRule.standalone(); + public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule(); private ProjectCleaner projectCleaner = mock(ProjectCleaner.class); private ConfigurationRepository settingsRepository = mock(ConfigurationRepository.class); private MutableDisabledComponentsHolder disabledComponentsHolder = mock(MutableDisabledComponentsHolder.class, RETURNS_DEEP_STUBS); - private PurgeDatastoresStep underTest = new PurgeDatastoresStep(mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS), projectCleaner, dbIdsRepository, treeRootHolder, - settingsRepository, disabledComponentsHolder); + private PurgeDatastoresStep underTest = new PurgeDatastoresStep(mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS), projectCleaner, treeRootHolder, + settingsRepository, disabledComponentsHolder, analysisMetadataHolder); + + @Before + public void before() { + analysisMetadataHolder.setProject(new Project("uuid", "key", "name", null, Collections.emptyList())); + } @Test public void call_purge_method_of_the_purge_task_for_project() { @@ -88,12 +94,7 @@ public class PurgeDatastoresStepTest extends BaseStepTest { @DataProvider public static Object[][] nonRootProjectComponentTypes() { - return dataproviderFromComponentTypeValues(new Predicate() { - @Override - public boolean apply(Component.Type input) { - return input.isReportType() && input != Component.Type.PROJECT; - } - }); + return dataproviderFromComponentTypeValues(input -> input.isReportType() && input != Component.Type.PROJECT); } @Test @@ -106,12 +107,7 @@ public class PurgeDatastoresStepTest extends BaseStepTest { @DataProvider public static Object[][] nonRootViewsComponentTypes() { - return dataproviderFromComponentTypeValues(new Predicate() { - @Override - public boolean apply(Component.Type input) { - return input.isViewsType() && input != Component.Type.VIEW; - } - }); + return dataproviderFromComponentTypeValues(input -> input.isViewsType() && input != Component.Type.VIEW); } @Test @@ -133,21 +129,19 @@ public class PurgeDatastoresStepTest extends BaseStepTest { private void verify_call_purge_method_of_the_purge_task(Component project) { treeRootHolder.setRoot(project); when(settingsRepository.getConfiguration()).thenReturn(new MapSettings().asConfig()); - dbIdsRepository.setComponentId(project, PROJECT_ID); underTest.execute(new TestComputationStepContext()); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(IdUuidPair.class); - verify(projectCleaner).purge(any(), argumentCaptor.capture(), any(), any()); - assertThat(argumentCaptor.getValue().getId()).isEqualTo(PROJECT_ID); - assertThat(argumentCaptor.getValue().getUuid()).isEqualTo(PROJECT_UUID); + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(String.class); + verify(projectCleaner).purge(any(), argumentCaptor.capture(), anyString(), any(), any()); + assertThat(argumentCaptor.getValue()).isEqualTo(PROJECT_UUID); } private static Object[][] dataproviderFromComponentTypeValues(Predicate predicate) { - return FluentIterable.from(asList(Component.Type.values())) + return Arrays.stream(Component.Type.values()) .filter(predicate) - .transform(WrapInSingleElementArray.INSTANCE) - .toArray(Object[].class); + .map(WrapInSingleElementArray.INSTANCE) + .toArray(Object[][]::new); } @Override diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeConfiguration.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeConfiguration.java index c7e46b549c6..0f4d1b3b1cb 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeConfiguration.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeConfiguration.java @@ -33,16 +33,18 @@ import org.sonar.core.config.PurgeConstants; public class PurgeConfiguration { - private final IdUuidPair rootProjectIdUuid; + private final String rootUuid; + private final String projectUuid; private final Collection scopesWithoutHistoricalData; private final int maxAgeInDaysOfClosedIssues; private final Optional maxAgeInDaysOfInactiveShortLivingBranches; private final System2 system2; private final Collection disabledComponentUuids; - public PurgeConfiguration(IdUuidPair rootProjectId, Collection scopesWithoutHistoricalData, int maxAgeInDaysOfClosedIssues, + public PurgeConfiguration(String rootUuid, String projectUuid, Collection scopesWithoutHistoricalData, int maxAgeInDaysOfClosedIssues, Optional maxAgeInDaysOfInactiveShortLivingBranches, System2 system2, Collection disabledComponentUuids) { - this.rootProjectIdUuid = rootProjectId; + this.rootUuid = rootUuid; + this.projectUuid = projectUuid; this.scopesWithoutHistoricalData = scopesWithoutHistoricalData; this.maxAgeInDaysOfClosedIssues = maxAgeInDaysOfClosedIssues; this.system2 = system2; @@ -50,13 +52,25 @@ public class PurgeConfiguration { this.maxAgeInDaysOfInactiveShortLivingBranches = maxAgeInDaysOfInactiveShortLivingBranches; } - public static PurgeConfiguration newDefaultPurgeConfiguration(Configuration config, IdUuidPair rootId, Collection disabledComponentUuids) { - return new PurgeConfiguration(rootId, Arrays.asList(Scopes.DIRECTORY, Scopes.FILE), config.getInt(PurgeConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES).get(), + public static PurgeConfiguration newDefaultPurgeConfiguration(Configuration config, String rootUuid, String projectUuid, Collection disabledComponentUuids) { + return new PurgeConfiguration(rootUuid, projectUuid, Arrays.asList(Scopes.DIRECTORY, Scopes.FILE), config.getInt(PurgeConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES).get(), config.getInt(PurgeConstants.DAYS_BEFORE_DELETING_INACTIVE_SHORT_LIVING_BRANCHES), System2.INSTANCE, disabledComponentUuids); } - public IdUuidPair rootProjectIdUuid() { - return rootProjectIdUuid; + /** + * UUID of the branch being analyzed (root of the component tree). Will be the same as {@link #projectUuid} + * if it's the main branch. + * Can also be a view. + */ + public String rootUuid() { + return rootUuid; + } + + /** + * @return UUID of the main branch of the project + */ + public String projectUuid() { + return projectUuid; } public Collection getScopesWithoutHistoricalData() { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java index 8e63cfd6f4e..d531bebcdca 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java @@ -61,7 +61,7 @@ public class PurgeDao implements Dao { public void purge(DbSession session, PurgeConfiguration conf, PurgeListener listener, PurgeProfiler profiler) { PurgeMapper mapper = session.getMapper(PurgeMapper.class); PurgeCommands commands = new PurgeCommands(session, mapper, profiler); - String rootUuid = conf.rootProjectIdUuid().getUuid(); + String rootUuid = conf.rootUuid(); deleteAbortedAnalyses(rootUuid, commands); deleteDataOfComponentsWithoutHistoricalData(session, rootUuid, conf.getScopesWithoutHistoricalData(), commands); purgeAnalyses(commands, rootUuid); @@ -78,10 +78,12 @@ public class PurgeDao implements Dao { } LOG.debug("<- Purge stale branches"); - List branchUuids = mapper.selectStaleShortLivingBranchesAndPullRequests(rootUuid, dateToLong(maxDate.get())); + List branchUuids = mapper.selectStaleShortLivingBranchesAndPullRequests(conf.projectUuid(), dateToLong(maxDate.get())); for (String branchUuid : branchUuids) { - deleteRootComponent(branchUuid, mapper, commands); + if (!rootUuid.equals(branchUuid)) { + deleteRootComponent(branchUuid, mapper, commands); + } } } @@ -96,7 +98,7 @@ public class PurgeDao implements Dao { private static void deleteOldClosedIssues(PurgeConfiguration conf, PurgeMapper mapper, PurgeListener listener) { Date toDate = conf.maxLiveDateOfClosedIssues(); - String rootUuid = conf.rootProjectIdUuid().getUuid(); + String rootUuid = conf.rootUuid(); List issueKeys = mapper.selectOldClosedIssueKeys(rootUuid, dateToLong(toDate)); executeLargeInputs(issueKeys, input -> { mapper.deleteIssueChangesFromIssueKeys(input); @@ -152,7 +154,7 @@ public class PurgeDao implements Dao { return emptyList(); }); - listener.onComponentsDisabling(conf.rootProjectIdUuid().getUuid(), conf.getDisabledComponentUuids()); + listener.onComponentsDisabling(conf.rootUuid(), conf.getDisabledComponentUuids()); session.commit(); } @@ -214,7 +216,7 @@ public class PurgeDao implements Dao { * Delete the non root components (ie. sub-view, application or project copy) from the specified collection of {@link ComponentDto} * and data from their child tables. *

- * This method has no effect when passed an empty collection or only root components. + * This method has no effect when passed an empty collection or only root components. *

*/ public void deleteNonRootComponentsInView(DbSession dbSession, Collection components) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java index 374671bf00c..bb15542e7ea 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java @@ -84,7 +84,7 @@ public interface PurgeMapper { List selectOldClosedIssueKeys(@Param("projectUuid") String projectUuid, @Nullable @Param("toDate") Long toDate); - List selectStaleShortLivingBranchesAndPullRequests(@Param("mainBranchProjectUuid") String mainBranchProjectUuid, @Param("toDate") Long toDate); + List selectStaleShortLivingBranchesAndPullRequests(@Param("projectUuid") String projectUuid, @Param("toDate") Long toDate); void deleteIssuesFromKeys(@Param("keys") List keys); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml index 2e2c1e395b9..95a420a0f08 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml @@ -52,7 +52,7 @@ from project_branches pb where - pb.project_uuid=#{mainBranchProjectUuid,jdbcType=VARCHAR} + pb.project_uuid=#{projectUuid,jdbcType=VARCHAR} and (pb.branch_type='SHORT' or pb.branch_type='PULL_REQUEST') and pb.updated_at < #{toDate} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeConfigurationTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeConfigurationTest.java index 914ad8d5cd8..03b6751da88 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeConfigurationTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeConfigurationTest.java @@ -36,10 +36,10 @@ import static org.assertj.core.api.Assertions.assertThat; public class PurgeConfigurationTest { @Test public void should_delete_all_closed_issues() { - PurgeConfiguration conf = new PurgeConfiguration(new IdUuidPair(1L, "1"), emptyList(), 0, Optional.empty(), System2.INSTANCE, emptyList()); + PurgeConfiguration conf = new PurgeConfiguration("root", "project", emptyList(), 0, Optional.empty(), System2.INSTANCE, emptyList()); assertThat(conf.maxLiveDateOfClosedIssues()).isNull(); - conf = new PurgeConfiguration(new IdUuidPair(1L, "1"), emptyList(), -1, Optional.empty(), System2.INSTANCE, emptyList()); + conf = new PurgeConfiguration("root", "project", emptyList(), -1, Optional.empty(), System2.INSTANCE, emptyList()); assertThat(conf.maxLiveDateOfClosedIssues()).isNull(); } @@ -47,7 +47,7 @@ public class PurgeConfigurationTest { public void should_delete_only_old_closed_issues() { Date now = DateUtils.parseDate("2013-05-18"); - PurgeConfiguration conf = new PurgeConfiguration(new IdUuidPair(1L, "1"), emptyList(), 30, Optional.empty(), System2.INSTANCE, emptyList()); + PurgeConfiguration conf = new PurgeConfiguration("root", "project", emptyList(), 30, Optional.empty(), System2.INSTANCE, emptyList()); Date toDate = conf.maxLiveDateOfClosedIssues(now); assertThat(toDate.getYear()).isEqualTo(113);// =2013 @@ -57,7 +57,7 @@ public class PurgeConfigurationTest { @Test public void should_have_empty_branch_purge_date() { - PurgeConfiguration conf = new PurgeConfiguration(new IdUuidPair(1L, "1"), emptyList(), 30, Optional.of(10), System2.INSTANCE, emptyList()); + PurgeConfiguration conf = new PurgeConfiguration("root", "project", emptyList(), 30, Optional.of(10), System2.INSTANCE, emptyList()); assertThat(conf.maxLiveDateOfInactiveShortLivingBranches()).isNotEmpty(); long tenDaysAgo = DateUtils.addDays(new Date(System2.INSTANCE.now()), -10).getTime(); assertThat(conf.maxLiveDateOfInactiveShortLivingBranches().get().getTime()).isBetween(tenDaysAgo - 5000, tenDaysAgo + 5000); @@ -65,7 +65,7 @@ public class PurgeConfigurationTest { @Test public void should_calculate_branch_purge_date() { - PurgeConfiguration conf = new PurgeConfiguration(new IdUuidPair(1L, "1"), emptyList(), 30, Optional.empty(), System2.INSTANCE, emptyList()); + PurgeConfiguration conf = new PurgeConfiguration("root", "project", emptyList(), 30, Optional.empty(), System2.INSTANCE, emptyList()); assertThat(conf.maxLiveDateOfInactiveShortLivingBranches()).isEmpty(); } @@ -75,7 +75,7 @@ public class PurgeConfigurationTest { settings.setProperty(PurgeConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES, 5); Date now = new Date(); - PurgeConfiguration underTest = PurgeConfiguration.newDefaultPurgeConfiguration(settings.asConfig(), new IdUuidPair(42L, "any-uuid"), emptyList()); + PurgeConfiguration underTest = PurgeConfiguration.newDefaultPurgeConfiguration(settings.asConfig(), "root", "project", emptyList()); assertThat(underTest.getScopesWithoutHistoricalData()) .containsExactlyInAnyOrder(Scopes.DIRECTORY, Scopes.FILE); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java index b50ecc58b1f..332dbb6fa6f 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java @@ -90,8 +90,7 @@ import static org.sonar.db.webhook.WebhookDeliveryTesting.selectAllDeliveryUuids public class PurgeDaoTest { - private static final String THE_PROJECT_UUID = "P1"; - private static final long THE_PROJECT_ID = 1L; + private static final String PROJECT_UUID = "P1"; private System2 system2 = mock(System2.class); @@ -142,7 +141,7 @@ public class PurgeDaoTest { // back to present when(system2.now()).thenReturn(new Date().getTime()); - underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid()), PurgeListener.EMPTY, new PurgeProfiler()); + underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid(), project.uuid()), PurgeListener.EMPTY, new PurgeProfiler()); dbSession.commit(); assertThat(uuidsIn("projects")).containsOnly(project.uuid(), longBranch.uuid(), recentShortBranch.uuid()); @@ -168,16 +167,43 @@ public class PurgeDaoTest { // back to present when(system2.now()).thenReturn(new Date().getTime()); - underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid()), PurgeListener.EMPTY, new PurgeProfiler()); + underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid(), project.uuid()), PurgeListener.EMPTY, new PurgeProfiler()); dbSession.commit(); assertThat(uuidsIn("projects")).containsOnly(project.uuid(), longBranch.uuid(), recentPullRequest.uuid()); } + @Test + public void purge_inactive_SLB_when_analyzing_non_main_branch() { + when(system2.now()).thenReturn(new Date().getTime()); + RuleDefinitionDto rule = db.rules().insert(); + ComponentDto project = db.components().insertMainBranch(); + ComponentDto longBranch = db.components().insertProjectBranch(project); + + when(system2.now()).thenReturn(DateUtils.addDays(new Date(), -31).getTime()); + + // SLB updated 31 days ago + ComponentDto slb1 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT)); + + // SLB with other components and issues, updated 31 days ago + ComponentDto slb2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST)); + ComponentDto file = db.components().insertComponent(newFileDto(slb2)); + db.issues().insert(rule, slb2, file); + + // back to present + when(system2.now()).thenReturn(new Date().getTime()); + // analysing slb1 + underTest.purge(dbSession, newConfigurationWith30Days(system2, slb1.uuid(), slb1.getMainBranchProjectUuid()), PurgeListener.EMPTY, new PurgeProfiler()); + dbSession.commit(); + + // slb1 wasn't deleted since it was being analyzed! + assertThat(uuidsIn("projects")).containsOnly(project.uuid(), longBranch.uuid(), slb1.uuid()); + } + @Test public void shouldDeleteHistoricalDataOfDirectoriesAndFiles() { db.prepareDbUnit(getClass(), "shouldDeleteHistoricalDataOfDirectoriesAndFiles.xml"); - PurgeConfiguration conf = new PurgeConfiguration(new IdUuidPair(THE_PROJECT_ID, "PROJECT_UUID"), asList(Scopes.DIRECTORY, Scopes.FILE), + PurgeConfiguration conf = new PurgeConfiguration("PROJECT_UUID", "PROJECT_UUID", asList(Scopes.DIRECTORY, Scopes.FILE), 30, Optional.of(30), System2.INSTANCE, Collections.emptyList()); underTest.purge(dbSession, conf, PurgeListener.EMPTY, new PurgeProfiler()); @@ -231,7 +257,7 @@ public class PurgeDaoTest { // back to present when(system2.now()).thenReturn(new Date().getTime()); - underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid(), module.uuid(), dir.uuid(), srcFile.uuid(), testFile.uuid()), PurgeListener.EMPTY, + underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid(), project.uuid(), module.uuid(), dir.uuid(), srcFile.uuid(), testFile.uuid()), PurgeListener.EMPTY, new PurgeProfiler()); dbSession.commit(); @@ -339,7 +365,7 @@ public class PurgeDaoTest { @Test public void selectPurgeableAnalyses() { db.prepareDbUnit(getClass(), "shouldSelectPurgeableAnalysis.xml"); - List analyses = underTest.selectPurgeableAnalyses(THE_PROJECT_UUID, dbSession); + List analyses = underTest.selectPurgeableAnalyses(PROJECT_UUID, dbSession); assertThat(analyses).hasSize(3); assertThat(getById(analyses, "u1").isLast()).isTrue(); @@ -869,7 +895,7 @@ public class PurgeDaoTest { IssueDto notClosed = db.issues().insert(rule, project, file); when(system2.now()).thenReturn(new Date().getTime()); - underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid()), PurgeListener.EMPTY, new PurgeProfiler()); + underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid(), project.uuid()), PurgeListener.EMPTY, new PurgeProfiler()); dbSession.commit(); // old closed got deleted @@ -1251,11 +1277,11 @@ public class PurgeDaoTest { } private static PurgeConfiguration newConfigurationWith30Days() { - return new PurgeConfiguration(new IdUuidPair(THE_PROJECT_ID, THE_PROJECT_UUID), emptyList(), 30, Optional.of(30), System2.INSTANCE, Collections.emptyList()); + return new PurgeConfiguration(PROJECT_UUID, PROJECT_UUID, emptyList(), 30, Optional.of(30), System2.INSTANCE, Collections.emptyList()); } - private static PurgeConfiguration newConfigurationWith30Days(System2 system2, String rootProjectUuid, String... disabledComponentUuids) { - return new PurgeConfiguration(new IdUuidPair(THE_PROJECT_ID, rootProjectUuid), emptyList(), 30, Optional.of(30), system2, asList(disabledComponentUuids)); + private static PurgeConfiguration newConfigurationWith30Days(System2 system2, String rootUuid, String projectUuid, String... disabledComponentUuids) { + return new PurgeConfiguration(rootUuid, projectUuid, emptyList(), 30, Optional.of(30), system2, asList(disabledComponentUuids)); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/util/WrapInSingleElementArray.java b/server/sonar-server/src/test/java/org/sonar/server/util/WrapInSingleElementArray.java index 97edaaa7254..e90a6a09414 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/util/WrapInSingleElementArray.java +++ b/server/sonar-server/src/test/java/org/sonar/server/util/WrapInSingleElementArray.java @@ -19,7 +19,7 @@ */ package org.sonar.server.util; -import com.google.common.base.Function; +import java.util.function.Function; import javax.annotation.Nonnull; public enum WrapInSingleElementArray implements Function { @@ -28,6 +28,6 @@ public enum WrapInSingleElementArray implements Function { @Override @Nonnull public Object[] apply(Object input) { - return new Object[]{input}; + return new Object[] {input}; } } -- 2.39.5