From c78548572983bd7df98bf8f0468cce100d30f1c1 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Fri, 30 Nov 2018 07:52:47 -0600 Subject: [PATCH] SONAR-11548 Fail CE if SLB/PR targets a branch containing modules --- .../component/ComponentUuidFactory.java | 2 +- .../step/ValidateProjectStep.java | 19 +++++-- .../step/ValidateProjectStepTest.java | 52 +++++++++++++++++++ .../org/sonar/db/component/ComponentDao.java | 8 ++- .../sonar/db/component/ComponentMapper.java | 4 +- .../sonar/db/component/ComponentMapper.xml | 9 ++++ 6 files changed, 86 insertions(+), 8 deletions(-) diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactory.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactory.java index 3a23ea8cbe1..11459ba43a7 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactory.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentUuidFactory.java @@ -61,7 +61,7 @@ public class ComponentUuidFactory { private static Map loadModulePathsByUuid(DbClient dbClient, DbSession dbSession, String rootKey, Supplier> reportModulesPath) { List moduleDtos = dbClient.componentDao() - .selectEnabledModulesFromProjectKey(dbSession, rootKey, false).stream() + .selectModulesFromProjectKey(dbSession, rootKey, false).stream() .filter(c -> Qualifiers.MODULE.equals(c.qualifier())) .collect(Collectors.toList()); diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java index 9e1d810b927..098e93732d7 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStep.java @@ -25,6 +25,7 @@ import java.util.Date; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import org.sonar.api.utils.MessageException; import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; import org.sonar.ce.task.projectanalysis.component.Component; @@ -40,7 +41,6 @@ import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.SnapshotDto; -import static com.google.common.collect.FluentIterable.from; import static java.lang.String.format; import static org.sonar.api.utils.DateUtils.formatDateTime; @@ -51,6 +51,7 @@ import static org.sonar.api.utils.DateUtils.formatDateTime; *
  • module key already exists in another project (same module key cannot exists in different projects)
  • *
  • module key is already used as a project key
  • *
  • date of the analysis is before last analysis
  • + *
  • short living branch or PR targets a branch that still contains modules
  • * */ public class ValidateProjectStep implements ComputationStep { @@ -70,9 +71,10 @@ public class ValidateProjectStep implements ComputationStep { @Override public void execute(ComputationStep.Context context) { try (DbSession dbSession = dbClient.openSession(false)) { + validateTargetBranch(dbSession); Component root = treeRootHolder.getRoot(); List baseModules = dbClient.componentDao().selectEnabledModulesFromProjectKey(dbSession, root.getDbKey()); - Map baseModulesByKey = from(baseModules).uniqueIndex(ComponentDto::getDbKey); + Map baseModulesByKey = baseModules.stream().collect(Collectors.toMap(ComponentDto::getDbKey, x -> x)); ValidateProjectsVisitor visitor = new ValidateProjectsVisitor(dbSession, dbClient.componentDao(), baseModulesByKey); new DepthTraversalTypeAwareCrawler(visitor).visit(root); @@ -82,6 +84,17 @@ public class ValidateProjectStep implements ComputationStep { } } + private void validateTargetBranch(DbSession session) { + if (!analysisMetadataHolder.isShortLivingBranch() && !analysisMetadataHolder.isPullRequest()) { + return; + } + String mergeBranchUuid = analysisMetadataHolder.getBranch().getMergeBranchUuid().get(); + int moduleCount = dbClient.componentDao().countEnabledModulesByProjectUuid(session, mergeBranchUuid); + if (moduleCount > 0) { + throw MessageException.of("Due to an upgrade, you need to re-analyze the target branch before analyzing this branch."); + } + } + @Override public String getDescription() { return "Validate project"; @@ -97,14 +110,12 @@ public class ValidateProjectStep implements ComputationStep { super(CrawlerDepthLimit.PROJECT, ComponentVisitor.Order.PRE_ORDER); this.session = session; this.componentDao = componentDao; - this.baseModulesByKey = baseModulesByKey; } @Override public void visitProject(Component rawProject) { String rawProjectKey = rawProject.getDbKey(); - Optional baseProject = loadBaseComponent(rawProjectKey); validateAnalysisDate(baseProject); } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java index 5f26eadf1e2..acf221596ca 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ValidateProjectStepTest.java @@ -20,6 +20,8 @@ package org.sonar.ce.task.projectanalysis.step; import java.util.Date; +import java.util.Optional; +import javax.annotation.Nullable; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -35,10 +37,14 @@ import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule; import org.sonar.ce.task.step.TestComputationStepContext; import org.sonar.db.DbClient; import org.sonar.db.DbTester; +import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.SnapshotTesting; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + public class ValidateProjectStepTest { static long DEFAULT_ANALYSIS_TIME = 1433131200000L; // 2015-06-01 @@ -63,6 +69,52 @@ public class ValidateProjectStepTest { ValidateProjectStep underTest = new ValidateProjectStep(dbClient, treeRootHolder, analysisMetadataHolder); + @Test + public void fail_if_pr_is_targeting_branch_with_modules() { + ComponentDto masterProject = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "ABCD") + .setDbKey(PROJECT_KEY); + ComponentDto branchProject = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "DEFG") + .setDbKey(PROJECT_KEY + ":BRANCH:branch"); + dbClient.componentDao().insert(dbTester.getSession(), masterProject); + dbClient.componentDao().insert(dbTester.getSession(), branchProject); + dbClient.componentDao().insert(dbTester.getSession(), ComponentTesting.newModuleDto(masterProject)); + setBranch(BranchType.SHORT, masterProject.uuid()); + dbTester.getSession().commit(); + + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("DEFG") + .setKey(branchProject.getDbKey()) + .build()); + + thrown.expect(MessageException.class); + thrown.expectMessage("Due to an upgrade, you need to re-analyze the target branch before analyzing this branch."); + underTest.execute(new TestComputationStepContext()); + } + + @Test + public void dont_fail_if_pr_is_targeting_branch_without_modules() { + ComponentDto masterProject = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "ABCD") + .setDbKey(PROJECT_KEY); + ComponentDto branchProject = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "DEFG") + .setDbKey(PROJECT_KEY + ":BRANCH:branch"); + dbClient.componentDao().insert(dbTester.getSession(), masterProject); + dbClient.componentDao().insert(dbTester.getSession(), branchProject); + setBranch(BranchType.SHORT, masterProject.uuid()); + dbTester.getSession().commit(); + + treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("DEFG") + .setKey(branchProject.getDbKey()) + .build()); + + underTest.execute(new TestComputationStepContext()); + } + + private void setBranch(BranchType type, @Nullable String mergeBranchUuid) { + Branch branch = mock(Branch.class); + when(branch.getType()).thenReturn(type); + when(branch.getMergeBranchUuid()).thenReturn(Optional.ofNullable(mergeBranchUuid)); + analysisMetadataHolder.setBranch(branch); + } + @Test public void not_fail_if_analysis_date_is_after_last_analysis() { ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY); 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 c0449b593e6..fe2f3941ab3 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 @@ -183,12 +183,16 @@ public class ComponentDao implements Dao { return mapper(session).selectUuidsByKeyFromProjectKey(projectKey); } - public List selectEnabledModulesFromProjectKey(DbSession session, String projectKey, boolean excludeDisabled) { + public List selectModulesFromProjectKey(DbSession session, String projectKey, boolean excludeDisabled) { return mapper(session).selectComponentsFromProjectKeyAndScope(projectKey, Scopes.PROJECT, excludeDisabled); } + public int countEnabledModulesByProjectUuid(DbSession session, String projectUuid) { + return mapper(session).countEnabledModulesByProjectUuid(projectUuid); + } + public List selectEnabledModulesFromProjectKey(DbSession session, String projectKey) { - return selectEnabledModulesFromProjectKey(session, projectKey, true); + return selectModulesFromProjectKey(session, projectKey, true); } public List selectByKeys(DbSession session, Collection keys) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java index f096156ed3c..7be4d074673 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentMapper.java @@ -66,11 +66,13 @@ public interface ComponentMapper { List selectComponentsByQualifiers(@Param("qualifiers") Collection qualifiers); + int countEnabledModulesByProjectUuid(@Param("projectUuid") String projectUuid); + /** * Counts the number of components with the specified id belonging to the specified organization. * * @return 1 or 0. Either because the organization uuid is not the one of the component or because the component does - * not exist. + * not exist. */ int countComponentByOrganizationAndId(@Param("organizationUuid") String organizationUuid, @Param("componentId") long componentId); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml index 77fd01b84ba..919e317a67c 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -279,6 +279,15 @@ + +