]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12636 set `excludeFromPurge` on branch creation based on global settings
authorMichal Duda <michal.duda@sonarsource.com>
Wed, 13 Nov 2019 13:16:48 +0000 (14:16 +0100)
committerSonarTech <sonartech@sonarsource.com>
Mon, 9 Dec 2019 19:46:15 +0000 (20:46 +0100)
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImpl.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/BranchPersisterImplTest.java
server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeConfiguration.java
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/component/ComponentDbTester.java
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest/schema.sql
server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/branch/ws/list-example.json
server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionActionTest.java
sonar-core/src/main/java/org/sonar/core/config/PurgeConstants.java

index a8bfb52aab22f98ed9f4cd9e736a6870caea824e..a9ad8dd70e09a5fdbfa75db922a06023324daf3a 100644 (file)
  */
 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<String> 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())) {
index 48691fc20ab16e4952bdcd28f0a284836e6fdc7c..c33dc5614dd094405b53044cfc7053ec8d954ca4 100644 (file)
@@ -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> 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> 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> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
+    assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
+  }
+
   @DataProvider
   public static Object[][] nullOrNotNullString() {
     return new Object[][] {
index dd5cb0d599d253321ce0339c1fdde1873963c2b8..7ca59766678dba5a5415165708980895545f436e 100644 (file)
@@ -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) {
index c707615368fa9b0d7b32ffa006113f201bef2c5d..0cb95299a388dc045ff65a56f4ef30ec2c844546 100644 (file)
@@ -55,7 +55,7 @@ public class PurgeConfiguration {
 
   public static PurgeConfiguration newDefaultPurgeConfiguration(Configuration config, String rootUuid, String projectUuid, Set<String> 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);
   }
 
   /**
index ac8ee748a01a2e3e7af57a30affa3f2eb69a7ba4..7c1f79e57019009ca02bc2c1f843211a957f69f2 100644 (file)
@@ -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();
index 367029ea6ba011b112320ebbd4d5efab7eaf7a09..45c10269b8d9cc5185ff04f27b139067f9ff9ca7 100644 (file)
@@ -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,
index fdd8e7f1f747cb7213cd8c2b8cf9251755e9cc6b..5a66497c31e9c45a150eecd466532c059ef4b622 100644 (file)
@@ -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);
   }
index 252fef00796f8eb18bd11eb4ea8d233e78fd6b49..e37bdebc9f16a0e8805e62ca64ce7ed147ff38b4 100644 (file)
@@ -18,7 +18,7 @@
         "qualityGateStatus": "ERROR"
       },
       "analysisDate": "2017-04-01T01:15:42+0100",
-      "excludedFromPurge": false
+      "excludedFromPurge": true
     }
   ]
 }
index bd500959d51c4a2e3170dd469542ca38e01d871e..3253663e6cfeabac64f211c6d59879e4cf8bddd5 100644 (file)
@@ -154,7 +154,7 @@ public class SetAutomaticDeletionProtectionActionTest {
     assertThat(db.countRowsOfTable("project_branches")).isEqualTo(2);
     Optional<BranchDto> 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> branchDto = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid());
     assertThat(branchDto.get().getKey()).isEqualTo("branch1");
index 160cef6ed9faf3ceb696418e30dcb8b2479d8644..06789a049ba6aba3f3e89ab036e264e02899fd62 100644 (file)
@@ -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";
 }