From 39f7a382198e93e0b818b34e1aa98da6c3a79f69 Mon Sep 17 00:00:00 2001 From: Michal Duda Date: Wed, 13 Nov 2019 14:16:48 +0100 Subject: [PATCH] SONAR-12636 set `excludeFromPurge` on branch creation based on global settings --- .../component/BranchPersisterImpl.java | 28 ++++++++-- .../component/BranchPersisterImplTest.java | 53 ++++++++++++++++++- .../org/sonar/db/component/BranchDto.java | 3 +- .../sonar/db/purge/PurgeConfiguration.java | 2 +- .../sonar/db/component/ComponentDbTester.java | 1 + .../schema.sql | 47 ++++++++++++++++ .../server/component/ComponentUpdater.java | 1 + .../sonar/server/branch/ws/list-example.json | 2 +- ...AutomaticDeletionProtectionActionTest.java | 2 +- .../org/sonar/core/config/PurgeConstants.java | 2 +- 10 files changed, 132 insertions(+), 9 deletions(-) diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java index a8bfb52aab2..a9ad8dd70e0 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java @@ -19,7 +19,10 @@ */ package org.sonar.ce.task.projectanalysis.component; +import java.util.List; +import java.util.regex.Pattern; import javax.annotation.Nullable; +import org.sonar.api.config.Configuration; import org.sonar.api.resources.Qualifiers; import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; import org.sonar.ce.task.projectanalysis.analysis.Branch; @@ -30,6 +33,10 @@ import org.sonar.db.component.BranchType; import org.sonar.db.component.ComponentDto; import org.sonar.db.protobuf.DbProjectBranches; +import static java.util.Arrays.asList; +import static java.util.Optional.ofNullable; +import static org.sonar.core.config.PurgeConstants.BRANCHES_TO_KEEP_WHEN_INACTIVE; + /** * Creates or updates the data in table {@code PROJECT_BRANCHES} for the current root. */ @@ -37,11 +44,14 @@ public class BranchPersisterImpl implements BranchPersister { private final DbClient dbClient; private final TreeRootHolder treeRootHolder; private final AnalysisMetadataHolder analysisMetadataHolder; + private final Configuration configuration; - public BranchPersisterImpl(DbClient dbClient, TreeRootHolder treeRootHolder, AnalysisMetadataHolder analysisMetadataHolder) { + public BranchPersisterImpl(DbClient dbClient, TreeRootHolder treeRootHolder, AnalysisMetadataHolder analysisMetadataHolder, + Configuration configuration) { this.dbClient = dbClient; this.treeRootHolder = treeRootHolder; this.analysisMetadataHolder = analysisMetadataHolder; + this.configuration = configuration; } public void persist(DbSession dbSession) { @@ -52,16 +62,28 @@ public class BranchPersisterImpl implements BranchPersister { .orElseThrow(() -> new IllegalStateException("Component has been deleted by end-user during analysis")); // insert or update in table project_branches - dbClient.branchDao().upsert(dbSession, toBranchDto(branchComponentDto, branch)); + dbClient.branchDao().upsert(dbSession, toBranchDto(branchComponentDto, branch, checkIfExcludedFromPurge())); + } + + private boolean checkIfExcludedFromPurge() { + if (analysisMetadataHolder.getBranch().isMain()) { + return true; + } + + List excludeFromPurgeEntries = asList(ofNullable(configuration.getStringArray(BRANCHES_TO_KEEP_WHEN_INACTIVE)).orElse(new String[0])); + return excludeFromPurgeEntries.stream() + .map(Pattern::compile) + .anyMatch(excludePattern -> excludePattern.matcher(analysisMetadataHolder.getBranch().getName()).matches()); } - protected BranchDto toBranchDto(ComponentDto componentDto, Branch branch) { + protected BranchDto toBranchDto(ComponentDto componentDto, Branch branch, boolean excludeFromPurge) { BranchDto dto = new BranchDto(); dto.setUuid(componentDto.uuid()); // MainBranchProjectUuid will be null if it's a main branch dto.setProjectUuid(firstNonNull(componentDto.getMainBranchProjectUuid(), componentDto.projectUuid())); dto.setBranchType(branch.getType()); + dto.setExcludeFromPurge(excludeFromPurge); // merge branch is only present if it's not a main branch and not an application if (!branch.isMain() && !Qualifiers.APP.equals(componentDto.qualifier())) { diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java index 48691fc20ab..c33dc5614dd 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java @@ -28,6 +28,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; +import org.sonar.api.config.Configuration; import org.sonar.api.utils.System2; import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule; import org.sonar.ce.task.projectanalysis.analysis.Branch; @@ -45,6 +46,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT; import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder; +import static org.sonar.core.config.PurgeConstants.BRANCHES_TO_KEEP_WHEN_INACTIVE; import static org.sonar.db.component.BranchType.BRANCH; import static org.sonar.db.component.BranchType.PULL_REQUEST; @@ -62,7 +64,9 @@ public class BranchPersisterImplTest { @Rule public ExpectedException exception = ExpectedException.none(); - private BranchPersister underTest = new BranchPersisterImpl(dbTester.getDbClient(), treeRootHolder, analysisMetadataHolder); + private Configuration configuration = mock(Configuration.class); + + private BranchPersister underTest = new BranchPersisterImpl(dbTester.getDbClient(), treeRootHolder, analysisMetadataHolder, configuration); @Test public void persist_fails_with_ISE_if_no_component_for_main_branches() { @@ -123,6 +127,53 @@ public class BranchPersisterImplTest { assertThat(branchDto.get().getPullRequestData()).isNull(); } + @Test + public void main_branch_is_excluded_from_branch_purge_by_default() { + analysisMetadataHolder.setBranch(createBranch(BRANCH, true, "master")); + treeRootHolder.setRoot(MAIN); + dbTester.components().insertMainBranch(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid())); + dbTester.commit(); + + underTest.persist(dbTester.getSession()); + + Optional branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), MAIN.getUuid()); + assertThat(branchDto.get().isExcludeFromPurge()).isTrue(); + } + + @Test + public void non_main_branch_is_excluded_from_branch_purge_if_matches_sonar_dbcleaner_keepFromPurge_property() { + when(configuration.getStringArray(BRANCHES_TO_KEEP_WHEN_INACTIVE)).thenReturn(new String[] {"BRANCH.*"}); + + analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY")); + treeRootHolder.setRoot(BRANCH1); + ComponentDto mainComponent = dbTester.components().insertMainBranch(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid())); + ComponentDto component = ComponentTesting.newProjectBranch(mainComponent, new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH)); + dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component); + dbTester.commit(); + + underTest.persist(dbTester.getSession()); + + Optional branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid()); + assertThat(branchDto.get().isExcludeFromPurge()).isTrue(); + } + + @Test + public void non_main_branch_is_included_in_branch_purge_if_branch_name_does_not_match_sonar_dbcleaner_keepFromPurge_property() { + when(configuration.getStringArray(BRANCHES_TO_KEEP_WHEN_INACTIVE)).thenReturn(new String[] {"foobar-.*"}); + + analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY")); + treeRootHolder.setRoot(BRANCH1); + ComponentDto mainComponent = dbTester.components().insertMainBranch(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid())); + ComponentDto component = ComponentTesting.newProjectBranch(mainComponent, new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH)); + dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component); + dbTester.commit(); + + underTest.persist(dbTester.getSession()); + + Optional branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid()); + assertThat(branchDto.get().isExcludeFromPurge()).isFalse(); + } + @DataProvider public static Object[][] nullOrNotNullString() { return new Object[][] { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java index dd5cb0d599d..7ca59766678 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java @@ -177,8 +177,9 @@ public class BranchDto { return excludeFromPurge; } - public void setExcludeFromPurge(boolean excludeFromPurge) { + public BranchDto setExcludeFromPurge(boolean excludeFromPurge) { this.excludeFromPurge = excludeFromPurge; + return this; } private static byte[] encodePullRequestData(DbProjectBranches.PullRequestData pullRequestData) { 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 c707615368f..0cb95299a38 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 @@ -55,7 +55,7 @@ public class PurgeConfiguration { public static PurgeConfiguration newDefaultPurgeConfiguration(Configuration config, String rootUuid, String projectUuid, Set 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_BRANCHES), System2.INSTANCE, disabledComponentUuids); + config.getInt(PurgeConstants.DAYS_BEFORE_DELETING_INACTIVE_BRANCHES_AND_PRS), System2.INSTANCE, disabledComponentUuids); } /** 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 ac8ee748a01..7c1f79e5701 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 @@ -253,6 +253,7 @@ public class ComponentDbTester { public final ComponentDto insertMainBranch(ComponentDto project) { BranchDto branchDto = ComponentTesting.newBranchDto(project, BRANCH); + branchDto.setExcludeFromPurge(true); insertComponent(project); dbClient.branchDao().insert(dbSession, branchDto); db.commit(); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest/schema.sql index 367029ea6ba..45c10269b8d 100644 --- a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest/schema.sql +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest/schema.sql @@ -1,3 +1,50 @@ +CREATE TABLE "PROJECTS" ( + "ID" INTEGER NOT NULL AUTO_INCREMENT (1,1), + "ORGANIZATION_UUID" VARCHAR(40) NOT NULL, + "KEE" VARCHAR(400), + "UUID" VARCHAR(50) NOT NULL, + "UUID_PATH" VARCHAR(1500) NOT NULL, + "ROOT_UUID" VARCHAR(50) NOT NULL, + "PROJECT_UUID" VARCHAR(50) NOT NULL, + "MODULE_UUID" VARCHAR(50), + "MODULE_UUID_PATH" VARCHAR(1500), + "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), + "NAME" VARCHAR(2000), + "DESCRIPTION" VARCHAR(2000), + "PRIVATE" BOOLEAN NOT NULL, + "TAGS" VARCHAR(500), + "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, + "SCOPE" VARCHAR(3), + "QUALIFIER" VARCHAR(10), + "DEPRECATED_KEE" VARCHAR(400), + "PATH" VARCHAR(2000), + "LANGUAGE" VARCHAR(20), + "COPY_COMPONENT_UUID" VARCHAR(50), + "LONG_NAME" VARCHAR(2000), + "DEVELOPER_UUID" VARCHAR(50), + "CREATED_AT" TIMESTAMP, + "AUTHORIZATION_UPDATED_AT" BIGINT, + "B_CHANGED" BOOLEAN, + "B_COPY_COMPONENT_UUID" VARCHAR(50), + "B_DESCRIPTION" VARCHAR(2000), + "B_ENABLED" BOOLEAN, + "B_UUID_PATH" VARCHAR(1500), + "B_LANGUAGE" VARCHAR(20), + "B_LONG_NAME" VARCHAR(500), + "B_MODULE_UUID" VARCHAR(50), + "B_MODULE_UUID_PATH" VARCHAR(1500), + "B_NAME" VARCHAR(500), + "B_PATH" VARCHAR(2000), + "B_QUALIFIER" VARCHAR(10) +); +CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID"); +CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); +CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); +CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); +CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); +CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); +CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); + CREATE TABLE "PROPERTIES" ( "ID" INTEGER NOT NULL AUTO_INCREMENT (1,1), "PROP_KEY" VARCHAR(512) NOT NULL, diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java index fdd8e7f1f74..5a66497c31e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java @@ -132,6 +132,7 @@ public class ComponentUpdater { .setUuid(componentUuid) .setKey(BranchDto.DEFAULT_MAIN_BRANCH_NAME) .setMergeBranchUuid(null) + .setExcludeFromPurge(true) .setProjectUuid(componentUuid); dbClient.branchDao().upsert(session, branch); } diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/branch/ws/list-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/branch/ws/list-example.json index 252fef00796..e37bdebc9f1 100644 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/branch/ws/list-example.json +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/branch/ws/list-example.json @@ -18,7 +18,7 @@ "qualityGateStatus": "ERROR" }, "analysisDate": "2017-04-01T01:15:42+0100", - "excludedFromPurge": false + "excludedFromPurge": true } ] } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionActionTest.java index bd500959d51..3253663e6cf 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionActionTest.java @@ -154,7 +154,7 @@ public class SetAutomaticDeletionProtectionActionTest { assertThat(db.countRowsOfTable("project_branches")).isEqualTo(2); Optional mainBranch = db.getDbClient().branchDao().selectByUuid(db.getSession(), project.uuid()); assertThat(mainBranch.get().getKey()).isEqualTo("master"); - assertThat(mainBranch.get().isExcludeFromPurge()).isFalse(); + assertThat(mainBranch.get().isExcludeFromPurge()).isTrue(); Optional branchDto = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid()); assertThat(branchDto.get().getKey()).isEqualTo("branch1"); diff --git a/sonar-core/src/main/java/org/sonar/core/config/PurgeConstants.java b/sonar-core/src/main/java/org/sonar/core/config/PurgeConstants.java index 160cef6ed9f..06789a049ba 100644 --- a/sonar-core/src/main/java/org/sonar/core/config/PurgeConstants.java +++ b/sonar-core/src/main/java/org/sonar/core/config/PurgeConstants.java @@ -27,6 +27,6 @@ public interface PurgeConstants { String WEEKS_BEFORE_KEEPING_ONLY_ANALYSES_WITH_VERSION = "sonar.dbcleaner.weeksBeforeKeepingOnlyAnalysesWithVersion"; String WEEKS_BEFORE_DELETING_ALL_SNAPSHOTS = "sonar.dbcleaner.weeksBeforeDeletingAllSnapshots"; String DAYS_BEFORE_DELETING_CLOSED_ISSUES = "sonar.dbcleaner.daysBeforeDeletingClosedIssues"; - String DAYS_BEFORE_DELETING_INACTIVE_BRANCHES = "sonar.dbcleaner.daysBeforeDeletingInactiveBranches"; + String DAYS_BEFORE_DELETING_INACTIVE_BRANCHES_AND_PRS = "sonar.dbcleaner.daysBeforeDeletingInactiveBranchesAndPRs"; String BRANCHES_TO_KEEP_WHEN_INACTIVE = "sonar.dbcleaner.branchesToKeepWhenInactive"; } -- 2.39.5