Bladeren bron

SONAR-12636 add a global setting that defines default list of branches to keep

tags/8.1.0.31237
Michal Duda 4 jaren geleden
bovenliggende
commit
d23f59d180
39 gewijzigde bestanden met toevoegingen van 1078 en 85 verwijderingen
  1. 5
    0
      server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java
  2. 19
    9
      server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java
  3. 4
    1
      server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java
  4. 6
    6
      server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeConfiguration.java
  5. 4
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java
  6. 1
    1
      server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
  7. 15
    3
      server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml
  8. 2
    2
      server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml
  9. 2
    1
      server/sonar-db-dao/src/schema/schema-sq.ddl
  10. 16
    0
      server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java
  11. 2
    1
      server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDtoTest.java
  12. 3
    3
      server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeConfigurationTest.java
  13. 27
    30
      server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
  14. 1
    2
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/DbVersion80.java
  15. 49
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/AddExcludeBranchFromPurgeColumn.java
  16. 4
    1
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java
  17. 106
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSetting.java
  18. 45
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/PopulateExcludeBranchFromPurgeColumn.java
  19. 94
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/AddExcludeBranchFromPurgeColumnTest.java
  20. 1
    1
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java
  21. 165
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest.java
  22. 109
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/PopulateExcludeBranchFromPurgeColumnTest.java
  23. 13
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v80/MakeExcludeBranchFromPurgeColumnNotNullableTest/schema.sql
  24. 12
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/AddExcludeBranchFromPurgeColumnTest/schema.sql
  25. 11
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest/schema.sql
  26. 13
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/PopulateExcludeBranchFromPurgeColumnTest/schema.sql
  27. 1
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/BranchWsModule.java
  28. 2
    2
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/BranchesWs.java
  29. 1
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/ListAction.java
  30. 2
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/ProjectBranchesParameters.java
  31. 98
    0
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionAction.java
  32. 4
    2
      server/sonar-webserver-webapi/src/main/resources/org/sonar/server/branch/ws/list-example.json
  33. 1
    1
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/BranchWsModuleTest.java
  34. 208
    0
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionActionTest.java
  35. 2
    1
      sonar-core/src/main/java/org/sonar/core/config/PurgeConstants.java
  36. 13
    15
      sonar-core/src/main/java/org/sonar/core/config/PurgeProperties.java
  37. 3
    0
      sonar-core/src/main/resources/org/sonar/l10n/core.properties
  38. 13
    1
      sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java
  39. 1
    0
      sonar-ws/src/main/protobuf/ws-projectbranches.proto

+ 5
- 0
server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDao.java Bestand weergeven

@@ -63,6 +63,11 @@ public class BranchDao implements Dao {
return mapper(dbSession).updateMainBranchName(projectUuid, newBranchKey, now);
}

public int updateExcludeFromPurge(DbSession dbSession, String branchUuid, boolean excludeFromPurge) {
long now = system2.now();
return mapper(dbSession).updateExcludeFromPurge(branchUuid, excludeFromPurge, now);
}

public Optional<BranchDto> selectByBranchKey(DbSession dbSession, String projectUuid, String key) {
return selectByKey(dbSession, projectUuid, key, KeyType.BRANCH);
}

+ 19
- 9
server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchDto.java Bestand weergeven

@@ -88,6 +88,8 @@ public class BranchDto {
@Nullable
private byte[] pullRequestBinary;

private boolean excludeFromPurge;

public String getUuid() {
return uuid;
}
@@ -171,6 +173,14 @@ public class BranchDto {
return decodePullRequestData(pullRequestBinary);
}

public boolean isExcludeFromPurge() {
return excludeFromPurge;
}

public void setExcludeFromPurge(boolean excludeFromPurge) {
this.excludeFromPurge = excludeFromPurge;
}

private static byte[] encodePullRequestData(DbProjectBranches.PullRequestData pullRequestData) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
@@ -212,14 +222,14 @@ public class BranchDto {

@Override
public String toString() {
return new StringBuilder("BranchDto{")
.append("uuid='").append(uuid).append('\'')
.append(", projectUuid='").append(projectUuid).append('\'')
.append(", kee='").append(kee).append('\'')
.append(", keyType=").append(keyType)
.append(", branchType=").append(branchType)
.append(", mergeBranchUuid='").append(mergeBranchUuid).append('\'')
.append('}')
.toString();
return "BranchDto{" +
"uuid='" + uuid + '\'' +
", projectUuid='" + projectUuid + '\'' +
", kee='" + kee + '\'' +
", keyType=" + keyType +
", branchType=" + branchType +
", mergeBranchUuid='" + mergeBranchUuid + '\'' +
", excludeFromPurge=" + excludeFromPurge +
'}';
}
}

+ 4
- 1
server/sonar-db-dao/src/main/java/org/sonar/db/component/BranchMapper.java Bestand weergeven

@@ -34,6 +34,9 @@ public interface BranchMapper {

int updateManualBaseline(@Param("uuid") String uuid, @Nullable @Param("analysisUuid") String analysisUuid, @Param("now") long now);

int updateExcludeFromPurge(@Param("uuid") String uuid, @Param("excludeFromPurge") boolean excludeFromPurge,
@Param("now") long now);

BranchDto selectByKey(@Param("projectUuid") String projectUuid, @Param("key") String key, @Param("keyType") KeyType keyType);

BranchDto selectByUuid(@Param("uuid") String uuid);
@@ -44,5 +47,5 @@ public interface BranchMapper {

long countNonMainBranches();

long countByTypeAndCreationDate(@Param("branchType")String branchType, @Param("sinceDate") long sinceDate);
long countByTypeAndCreationDate(@Param("branchType") String branchType, @Param("sinceDate") long sinceDate);
}

+ 6
- 6
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeConfiguration.java Bestand weergeven

@@ -38,24 +38,24 @@ public class PurgeConfiguration {
private final String projectUuid;
private final Collection<String> scopesWithoutHistoricalData;
private final int maxAgeInDaysOfClosedIssues;
private final Optional<Integer> maxAgeInDaysOfInactiveShortLivingBranches;
private final Optional<Integer> maxAgeInDaysOfInactiveBranches;
private final System2 system2;
private final Set<String> disabledComponentUuids;

public PurgeConfiguration(String rootUuid, String projectUuid, Collection<String> scopesWithoutHistoricalData, int maxAgeInDaysOfClosedIssues,
Optional<Integer> maxAgeInDaysOfInactiveShortLivingBranches, System2 system2, Set<String> disabledComponentUuids) {
Optional<Integer> maxAgeInDaysOfInactiveBranches, System2 system2, Set<String> disabledComponentUuids) {
this.rootUuid = rootUuid;
this.projectUuid = projectUuid;
this.scopesWithoutHistoricalData = scopesWithoutHistoricalData;
this.maxAgeInDaysOfClosedIssues = maxAgeInDaysOfClosedIssues;
this.system2 = system2;
this.disabledComponentUuids = disabledComponentUuids;
this.maxAgeInDaysOfInactiveShortLivingBranches = maxAgeInDaysOfInactiveShortLivingBranches;
this.maxAgeInDaysOfInactiveBranches = maxAgeInDaysOfInactiveBranches;
}

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_SHORT_LIVING_BRANCHES), System2.INSTANCE, disabledComponentUuids);
config.getInt(PurgeConstants.DAYS_BEFORE_DELETING_INACTIVE_BRANCHES), System2.INSTANCE, disabledComponentUuids);
}

/**
@@ -87,8 +87,8 @@ public class PurgeConfiguration {
return maxLiveDateOfClosedIssues(new Date(system2.now()));
}

public Optional<Date> maxLiveDateOfInactiveShortLivingBranches() {
return maxAgeInDaysOfInactiveShortLivingBranches.map(age -> DateUtils.addDays(new Date(system2.now()), -age));
public Optional<Date> maxLiveDateOfInactiveBranches() {
return maxAgeInDaysOfInactiveBranches.map(age -> DateUtils.addDays(new Date(system2.now()), -age));
}

@VisibleForTesting

+ 4
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java Bestand weergeven

@@ -41,6 +41,7 @@ import org.sonar.db.component.ComponentTreeQuery;
import org.sonar.db.component.ComponentTreeQuery.Strategy;

import static java.util.Collections.emptyList;
import static java.util.Optional.ofNullable;
import static org.sonar.api.utils.DateUtils.dateToLong;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;

@@ -75,14 +76,15 @@ public class PurgeDao implements Dao {
}

private static void purgeStaleBranches(PurgeCommands commands, PurgeConfiguration conf, PurgeMapper mapper, String rootUuid) {
Optional<Date> maxDate = conf.maxLiveDateOfInactiveShortLivingBranches();
Optional<Date> maxDate = conf.maxLiveDateOfInactiveBranches();
if (!maxDate.isPresent()) {
// not available if branch plugin is not installed
return;
}
LOG.debug("<- Purge stale branches");

List<String> branchUuids = mapper.selectStaleShortLivingBranchesAndPullRequests(conf.projectUuid(), dateToLong(maxDate.get()));
Long maxDateValue = ofNullable(dateToLong(maxDate.get())).orElseThrow(IllegalStateException::new);
List<String> branchUuids = mapper.selectStaleBranchesAndPullRequests(conf.projectUuid(), maxDateValue);

for (String branchUuid : branchUuids) {
if (!rootUuid.equals(branchUuid)) {

+ 1
- 1
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java Bestand weergeven

@@ -94,7 +94,7 @@ public interface PurgeMapper {

List<String> selectOldClosedIssueKeys(@Param("projectUuid") String projectUuid, @Nullable @Param("toDate") Long toDate);

List<String> selectStaleShortLivingBranchesAndPullRequests(@Param("projectUuid") String projectUuid, @Param("toDate") Long toDate);
List<String> selectStaleBranchesAndPullRequests(@Param("projectUuid") String projectUuid, @Param("toDate") Long toDate);

@CheckForNull
String selectSpecificAnalysisNewCodePeriod(@Param("projectUuid") String projectUuid);

+ 15
- 3
server/sonar-db-dao/src/main/resources/org/sonar/db/component/BranchMapper.xml Bestand weergeven

@@ -9,7 +9,8 @@
pb.key_type as keyType,
pb.branch_type as branchType,
pb.merge_branch_uuid as mergeBranchUuid,
pb.pull_request_binary as pullRequestBinary
pb.pull_request_binary as pullRequestBinary,
pb.exclude_from_purge as excludeFromPurge
</sql>

<insert id="insert" parameterType="map" useGeneratedKeys="false">
@@ -22,7 +23,8 @@
merge_branch_uuid,
pull_request_binary,
created_at,
updated_at
updated_at,
exclude_from_purge
) values (
#{dto.uuid, jdbcType=VARCHAR},
#{dto.projectUuid, jdbcType=VARCHAR},
@@ -32,7 +34,8 @@
#{dto.mergeBranchUuid, jdbcType=VARCHAR},
#{dto.pullRequestBinary, jdbcType=BINARY},
#{now, jdbcType=BIGINT},
#{now, jdbcType=BIGINT}
#{now, jdbcType=BIGINT},
#{dto.excludeFromPurge, jdbcType=BOOLEAN}
)
</insert>

@@ -45,6 +48,15 @@
uuid = #{projectUuid, jdbcType=VARCHAR}
</update>

<update id="updateExcludeFromPurge">
update project_branches
set
exclude_from_purge = #{excludeFromPurge, jdbcType=BOOLEAN},
updated_at = #{now, jdbcType=BIGINT}
where
uuid = #{uuid, jdbcType=VARCHAR}
</update>

<update id="update" parameterType="map" useGeneratedKeys="false">
update project_branches
set

+ 2
- 2
server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml Bestand weergeven

@@ -47,14 +47,14 @@
AND ncp.branch_uuid=#{projectUuid,jdbcType=VARCHAR}
</select>

<select id="selectStaleShortLivingBranchesAndPullRequests" parameterType="map" resultType="String">
<select id="selectStaleBranchesAndPullRequests" parameterType="map" resultType="String">
select
pb.uuid
from
project_branches pb
where
pb.project_uuid=#{projectUuid,jdbcType=VARCHAR}
and (pb.branch_type='SHORT' or pb.branch_type='PULL_REQUEST')
and pb.exclude_from_purge = ${_false}
and pb.updated_at &lt; #{toDate}
</select>


+ 2
- 1
server/sonar-db-dao/src/schema/schema-sq.ddl Bestand weergeven

@@ -591,7 +591,8 @@ CREATE TABLE "PROJECT_BRANCHES"(
"PULL_REQUEST_BINARY" BLOB,
"MANUAL_BASELINE_ANALYSIS_UUID" VARCHAR(40),
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL
"UPDATED_AT" BIGINT NOT NULL,
"EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL
);
ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID");
CREATE UNIQUE INDEX "PROJECT_BRANCHES_KEE_KEY_TYPE" ON "PROJECT_BRANCHES"("PROJECT_UUID", "KEE", "KEY_TYPE");

+ 16
- 0
server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDaoTest.java Bestand weergeven

@@ -101,6 +101,22 @@ public class BranchDaoTest {
assertThat(loaded.getBranchType()).isEqualTo(BranchType.LONG);
}

@Test
public void updateExcludeFromPurge() {
BranchDto dto = new BranchDto();
dto.setProjectUuid("U1");
dto.setUuid("U1");
dto.setBranchType(BranchType.LONG);
dto.setKey("feature");
dto.setExcludeFromPurge(false);
underTest.insert(dbSession, dto);

underTest.updateExcludeFromPurge(dbSession, "U1", true);

BranchDto loaded = underTest.selectByBranchKey(dbSession, "U1", "feature").get();
assertThat(loaded.isExcludeFromPurge()).isTrue();
}

@DataProvider
public static Object[][] nullOrEmpty() {
return new Object[][] {

+ 2
- 1
server/sonar-db-dao/src/test/java/org/sonar/db/component/BranchDtoTest.java Bestand weergeven

@@ -56,9 +56,10 @@ public class BranchDtoTest {
underTest.setKey("K1");
underTest.setBranchType(BranchType.LONG);
underTest.setMergeBranchUuid("U3");
underTest.setExcludeFromPurge(true);

assertThat(underTest.toString()).isEqualTo("BranchDto{uuid='U1', " +
"projectUuid='U2', kee='K1', keyType=null, branchType=LONG, mergeBranchUuid='U3'}");
"projectUuid='U2', kee='K1', keyType=null, branchType=LONG, mergeBranchUuid='U3', excludeFromPurge=true}");
}

@Test

+ 3
- 3
server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeConfigurationTest.java Bestand weergeven

@@ -58,15 +58,15 @@ public class PurgeConfigurationTest {
@Test
public void should_have_empty_branch_purge_date() {
PurgeConfiguration conf = new PurgeConfiguration("root", "project", emptySet(), 30, Optional.of(10), System2.INSTANCE, emptySet());
assertThat(conf.maxLiveDateOfInactiveShortLivingBranches()).isNotEmpty();
assertThat(conf.maxLiveDateOfInactiveBranches()).isNotEmpty();
long tenDaysAgo = DateUtils.addDays(new Date(System2.INSTANCE.now()), -10).getTime();
assertThat(conf.maxLiveDateOfInactiveShortLivingBranches().get().getTime()).isBetween(tenDaysAgo - 5000, tenDaysAgo + 5000);
assertThat(conf.maxLiveDateOfInactiveBranches().get().getTime()).isBetween(tenDaysAgo - 5000, tenDaysAgo + 5000);
}

@Test
public void should_calculate_branch_purge_date() {
PurgeConfiguration conf = new PurgeConfiguration("root", "project", emptySet(), 30, Optional.empty(), System2.INSTANCE, emptySet());
assertThat(conf.maxLiveDateOfInactiveShortLivingBranches()).isEmpty();
assertThat(conf.maxLiveDateOfInactiveBranches()).isEmpty();
}

@Test

+ 27
- 30
server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java Bestand weergeven

@@ -127,7 +127,7 @@ public class PurgeDaoTest {
public void purge_failed_ce_tasks() {
ComponentDto project = db.components().insertPrivateProject();
SnapshotDto pastAnalysis = db.components().insertSnapshot(project, t -> t.setStatus(STATUS_PROCESSED).setLast(false));
SnapshotDto toBeDeletedAnalysis = db.components().insertSnapshot(project, t -> t.setStatus(STATUS_UNPROCESSED).setLast(false));
db.components().insertSnapshot(project, t -> t.setStatus(STATUS_UNPROCESSED).setLast(false));
SnapshotDto lastAnalysis = db.components().insertSnapshot(project, t -> t.setStatus(STATUS_PROCESSED).setLast(true));

underTest.purge(dbSession, newConfigurationWith30Days(project.uuid()), PurgeListener.EMPTY, new PurgeProfiler());
@@ -137,27 +137,27 @@ public class PurgeDaoTest {
}

@Test
public void purge_inactive_short_living_branches() {
public void purge_inactive_branches() {
when(system2.now()).thenReturn(new Date().getTime());
RuleDefinitionDto rule = db.rules().insert();
ComponentDto project = db.components().insertMainBranch();
ComponentDto longBranch = db.components().insertProjectBranch(project);
ComponentDto recentShortBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT));
ComponentDto branch1 = db.components().insertProjectBranch(project);
ComponentDto branch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH));

// short branch with other components and issues, updated 31 days ago
// branch with other components and issues, updated 31 days ago
when(system2.now()).thenReturn(DateUtils.addDays(new Date(), -31).getTime());
ComponentDto shortBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.SHORT));
ComponentDto module = db.components().insertComponent(newModuleDto(shortBranch));
ComponentDto branch3 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH));
ComponentDto module = db.components().insertComponent(newModuleDto(branch3));
ComponentDto subModule = db.components().insertComponent(newModuleDto(module));
ComponentDto file = db.components().insertComponent(newFileDto(subModule));
db.issues().insert(rule, shortBranch, file);
db.issues().insert(rule, shortBranch, subModule);
db.issues().insert(rule, shortBranch, module);
db.issues().insert(rule, branch3, file);
db.issues().insert(rule, branch3, subModule);
db.issues().insert(rule, branch3, module);

underTest.purge(dbSession, newConfigurationWith30Days(System2.INSTANCE, project.uuid(), project.uuid()), PurgeListener.EMPTY, new PurgeProfiler());
dbSession.commit();

assertThat(uuidsIn("projects")).containsOnly(project.uuid(), longBranch.uuid(), recentShortBranch.uuid());
assertThat(uuidsIn("projects")).containsOnly(project.uuid(), branch1.uuid(), branch2.uuid());
}

@Test
@@ -185,7 +185,7 @@ public class PurgeDaoTest {
}

@Test
public void purge_inactive_SLB_when_analyzing_non_main_branch() {
public void purge_inactive_branches_when_analyzing_non_main_branch() {
when(system2.now()).thenReturn(new Date().getTime());
RuleDefinitionDto rule = db.rules().insert();
ComponentDto project = db.components().insertMainBranch();
@@ -193,22 +193,22 @@ public class PurgeDaoTest {

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));
// branch updated 31 days ago
ComponentDto branch1 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH));

// 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);
// branch with other components and issues, updated 31 days ago
ComponentDto branch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST));
ComponentDto file = db.components().insertComponent(newFileDto(branch2));
db.issues().insert(rule, branch2, 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());
// analysing branch1
underTest.purge(dbSession, newConfigurationWith30Days(system2, branch1.uuid(), branch1.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());
// branch1 wasn't deleted since it was being analyzed!
assertThat(uuidsIn("projects")).containsOnly(project.uuid(), longBranch.uuid(), branch1.uuid());
}

@Test
@@ -483,8 +483,7 @@ public class PurgeDaoTest {
.setProjectUuid(project1.uuid())
.setBranchUuid(project1.uuid())
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS)
.setValue(analysis1.getUuid())
);
.setValue(analysis1.getUuid()));
ComponentDto project2 = db.components().insertPrivateProject();
SnapshotDto analysis2 = db.components().insertSnapshot(newSnapshot()
.setComponentUuid(project2.uuid())
@@ -510,8 +509,7 @@ public class PurgeDaoTest {
.setProjectUuid(project.uuid())
.setBranchUuid(project.uuid())
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS)
.setValue(analysisProject.getUuid())
);
.setValue(analysisProject.getUuid()));
ComponentDto branch1 = db.components().insertProjectBranch(project);
SnapshotDto analysisBranch1 = db.components().insertSnapshot(newSnapshot()
.setComponentUuid(branch1.uuid())
@@ -527,8 +525,7 @@ public class PurgeDaoTest {
.setProjectUuid(project.uuid())
.setBranchUuid(branch2.uuid())
.setType(NewCodePeriodType.SPECIFIC_ANALYSIS)
.setValue(analysisBranch2.getUuid())
);
.setValue(analysisBranch2.getUuid()));
dbSession.commit();

assertThat(underTest.selectPurgeableAnalyses(project.uuid(), dbSession))
@@ -1178,8 +1175,8 @@ public class PurgeDaoTest {
@Test
public void delete_ce_analysis_older_than_180_and_scanner_context_older_than_40_days_of_project_and_branches_when_purging_project() {
LocalDateTime now = LocalDateTime.now();
ComponentDto project1 = db.components().insertPublicProject();
ComponentDto branch1 = db.components().insertProjectBranch(project1);
ComponentDto project1 = db.components().insertMainBranch();
ComponentDto branch1 = db.components().insertProjectBranch(project1, b -> b.setExcludeFromPurge(true));
Consumer<CeQueueDto> belongsToProject1 = t -> t.setMainComponentUuid(project1.uuid()).setComponentUuid(project1.uuid());
Consumer<CeQueueDto> belongsToBranch1 = t -> t.setMainComponentUuid(project1.uuid()).setComponentUuid(branch1.uuid());


+ 1
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v80/DbVersion80.java Bestand weergeven

@@ -35,7 +35,6 @@ public class DbVersion80 implements DbVersion {
.add(3006, "Create NEW_CODE_PERIOD table", CreateNewCodePeriodTable.class)
.add(3007, "Populate NEW_CODE_PERIOD table", PopulateNewCodePeriodTable.class)
.add(3008, "Remove leak period properties", RemoveLeakPeriodProperties.class)
.add(3009, "Remove GitHub login generation strategy property", RemoveGitHubLoginGenerationStrategyProperty.class)
;
.add(3009, "Remove GitHub login generation strategy property", RemoveGitHubLoginGenerationStrategyProperty.class);
}
}

+ 49
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/AddExcludeBranchFromPurgeColumn.java Bestand weergeven

@@ -0,0 +1,49 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.platform.db.migration.version.v81;

import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.SupportsBlueGreen;
import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
import org.sonar.server.platform.db.migration.step.DdlChange;

import static org.sonar.server.platform.db.migration.def.BooleanColumnDef.newBooleanColumnDefBuilder;

@SupportsBlueGreen
public class AddExcludeBranchFromPurgeColumn extends DdlChange {
private static final String TABLE = "project_branches";
private static final String NEW_COLUMN = "exclude_from_purge";

public AddExcludeBranchFromPurgeColumn(Database db) {
super(db);
}

@Override
public void execute(Context context) throws SQLException {
context.execute(new AddColumnsBuilder(getDialect(), TABLE)
.addColumn(newBooleanColumnDefBuilder()
.setColumnName(NEW_COLUMN)
.setIsNullable(false)
.setDefaultValue(false)
.build())
.build());
}
}

+ 4
- 1
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java Bestand weergeven

@@ -32,6 +32,9 @@ public class DbVersion81 implements DbVersion {
.add(3103, "Migrate GitHub ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateGithubAlmSettings.class)
.add(3104, "Migrate Bitbucket ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateBitbucketAlmSettings.class)
.add(3105, "Migrate Azure ALM settings from PROPERTIES to ALM_SETTINGS tables", MigrateAzureAlmSettings.class)
.add(3106, "Delete 'sonar.pullrequest.provider' property", DeleteSonarPullRequestProviderProperty.class);
.add(3106, "Delete 'sonar.pullrequest.provider' property", DeleteSonarPullRequestProviderProperty.class)
.add(3107, "Migrate default branches to keep global setting", MigrateDefaultBranchesToKeepSetting.class)
.add(3108, "Add EXCLUDE_FROM_PURGE column", AddExcludeBranchFromPurgeColumn.class)
.add(3109, "Populate EXCLUDE_FROM_PURGE column", PopulateExcludeBranchFromPurgeColumn.class);
}
}

+ 106
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSetting.java Bestand weergeven

@@ -0,0 +1,106 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.platform.db.migration.version.v81;

import java.sql.SQLException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.SupportsBlueGreen;
import org.sonar.server.platform.db.migration.step.DataChange;
import org.sonar.server.platform.db.migration.step.MassUpdate;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;

@SupportsBlueGreen
public class MigrateDefaultBranchesToKeepSetting extends DataChange {
private static final Logger LOG = Loggers.get(MigrateDefaultBranchesToKeepSetting.class);
private static final String DEPRECATED_KEY = "sonar.branch.longLivedBranches.regex";
private static final String NEW_KEY = "sonar.dbcleaner.branchesToKeepWhenInactive";

private final System2 system;

public MigrateDefaultBranchesToKeepSetting(Database db, System2 system) {
super(db);
this.system = system;
}

@Override
protected void execute(Context context) throws SQLException {
Long now = system.now();
try {
Long numberOfNewProps = context.prepareSelect("select count(*) from properties props where props.prop_key = '" + NEW_KEY + "'")
.get(row -> row.getLong(1));
if (numberOfNewProps != null && numberOfNewProps > 0) {
// no need for a migration
return;
}

Boolean defaultPropertyOverridden = context.prepareSelect("select count(*) from properties props where props.prop_key = '" + DEPRECATED_KEY + "'")
.get(row -> row.getLong(1) > 0);
if (FALSE.equals(defaultPropertyOverridden)) {
migrateDefaultDeprecatedSettings(context, now);
} else {
migrateOverriddenDeprecatedSettings(context, now);
}
} catch (Exception ex) {
LOG.error("Failed to migrate to new '{}' setting.", NEW_KEY);
throw ex;
}
}

private static void migrateDefaultDeprecatedSettings(Context context, Long time) throws SQLException {
Boolean anyProjectAlreadyExists = context.prepareSelect("select count(*) from projects").get(row -> row.getLong(1) > 0);
String newSettingValue = "master,develop,trunk";

// if old `sonar.branch.longLivedBranches.regex` setting was at default value but there were already projects analyzed we need to add the
// old defaults of
// that setting to the defaults of the new `sonar.dbcleaner.branchesToKeepWhenInactive` setting for backward compatibility
if (TRUE.equals(anyProjectAlreadyExists)) {
newSettingValue = "master,develop,trunk,branch-.*,release-.*";
}

context
.prepareUpsert("insert into properties (prop_key, is_empty, text_value, created_at) values (?, ?, ?, ?)")
.setString(1, NEW_KEY)
.setBoolean(2, false)
.setString(3, newSettingValue)
.setLong(4, time)
.execute()
.commit();
}

private static void migrateOverriddenDeprecatedSettings(Context context, Long time) throws SQLException {
MassUpdate massUpdate = context.prepareMassUpdate();
massUpdate.select("select resource_id, text_value from properties props where props.prop_key = '" + DEPRECATED_KEY + "'");
massUpdate.rowPluralName("properties");
massUpdate.update("insert into properties (resource_id, prop_key, is_empty, text_value, created_at) values (?, ?, ?, ?, ?)");
massUpdate.execute((row, update) -> {
update.setLong(1, row.getNullableLong(1));
update.setString(2, NEW_KEY);
update.setBoolean(3, false);
update.setString(4, row.getString(2));
update.setLong(5, time);
return true;
});
}
}

+ 45
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/PopulateExcludeBranchFromPurgeColumn.java Bestand weergeven

@@ -0,0 +1,45 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.platform.db.migration.version.v81;

import java.sql.SQLException;
import org.sonar.api.utils.System2;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.SupportsBlueGreen;
import org.sonar.server.platform.db.migration.step.DataChange;

@SupportsBlueGreen
public class PopulateExcludeBranchFromPurgeColumn extends DataChange {
private final System2 system;

public PopulateExcludeBranchFromPurgeColumn(Database db, System2 system) {
super(db);
this.system = system;
}

@Override
public void execute(Context context) throws SQLException {
Long now = system.now();
context.prepareUpsert("update project_branches set exclude_from_purge = true, updated_at = ? where branch_type = 'LONG'")
.setLong(1, now)
.execute()
.commit();
}
}

+ 94
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/AddExcludeBranchFromPurgeColumnTest.java Bestand weergeven

@@ -0,0 +1,94 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.platform.db.migration.version.v81;

import java.sql.SQLException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.db.CoreDbTester;

import static org.assertj.core.api.Assertions.assertThat;

public class AddExcludeBranchFromPurgeColumnTest {

private static final String TABLE = "project_branches";

private static final String PROJECT_1_UUID = "1a724f54-c2a4-4d36-b59c-61026f178613";
private static final String PROJECT_2_UUID = "cc69ccb8-434a-489b-abd6-6a80371f64ff";

private static final String MAIN_BRANCH_1 = "8a9789c8-7aee-4aa6-9cb7-407137935ac3";
private static final String LONG_BRANCH_1 = "69fdfc19-491c-4ed9-bcac-ef04e0f6cdc6";
private static final String SHORT_BRANCH_1 = "f7a6d247-1790-40f8-8591-a0cc39d05ecb";
private static final String PR_1 = "d65466bf-271c-4f9f-ac7a-72add44848c0";

private static final String MAIN_BRANCH_2 = "cdadf128-7bdb-4589-982d-62445d46ae1b";
private static final String LONG_BRANCH_2 = "60bf6fa8-3ecc-4ba6-ad8d-991ea7c7f9cb";
private static final String SHORT_BRANCH_2 = "ce5632ed-462e-4384-98b6-1773a7bbfe53";
private static final String PR_2 = "5897f7d0-d34f-4558-b9c5-a7eb7a5c4b69";

@Rule
public CoreDbTester dbTester = CoreDbTester.createForSchema(AddExcludeBranchFromPurgeColumnTest.class, "schema.sql");

@Rule
public ExpectedException expectedException = ExpectedException.none();

private AddExcludeBranchFromPurgeColumn underTest = new AddExcludeBranchFromPurgeColumn(dbTester.database());

@Before
public void setup() {
insertBranch(MAIN_BRANCH_1, PROJECT_1_UUID, "master", "BRANCH", "LONG");
insertBranch(LONG_BRANCH_1, PROJECT_1_UUID, "release-1", "BRANCH", "LONG");
insertBranch(SHORT_BRANCH_1, PROJECT_1_UUID, "feature/foo", "BRANCH", "SHORT");
insertBranch(PR_1, PROJECT_1_UUID, "feature/feature-1", "PULL_REQUEST", "PULL_REQUEST");

insertBranch(MAIN_BRANCH_2, PROJECT_2_UUID, "trunk", "BRANCH", "LONG");
insertBranch(LONG_BRANCH_2, PROJECT_2_UUID, "branch-1", "BRANCH", "LONG");
insertBranch(SHORT_BRANCH_2, PROJECT_2_UUID, "feature/bar", "BRANCH", "SHORT");
insertBranch(PR_2, PROJECT_2_UUID, "feature/feature-2", "PULL_REQUEST", "PULL_REQUEST");
}

@Test
public void execute_migration() throws SQLException {
underTest.execute();

verifyMigrationResult();
}

private void verifyMigrationResult() {
assertThat(dbTester.countSql("select count(*) from " + TABLE + " where exclude_from_purge = true")).isEqualTo(0);
assertThat(dbTester.countSql("select count(*) from " + TABLE + " where exclude_from_purge = false")).isEqualTo(8);
}

private void insertBranch(String uuid, String projectUuid, String key, String keyType, String branchType) {
dbTester.executeInsert(
TABLE,
"UUID", uuid,
"PROJECT_UUID", projectUuid,
"KEE", key,
"BRANCH_TYPE", branchType,
"KEY_TYPE", keyType,
"MERGE_BRANCH_UUID", null,
"CREATED_AT", System2.INSTANCE.now(),
"UPDATED_AT", System2.INSTANCE.now());
}
}

+ 1
- 1
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java Bestand weergeven

@@ -37,7 +37,7 @@ public class DbVersion81Test {

@Test
public void verify_migration_count() {
verifyMigrationCount(underTest, 7);
verifyMigrationCount(underTest, 10);
}

}

+ 165
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest.java Bestand weergeven

@@ -0,0 +1,165 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.platform.db.migration.version.v81;

import java.sql.SQLException;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.core.util.Uuids;
import org.sonar.db.CoreDbTester;

import static org.assertj.core.api.Assertions.assertThat;

public class MigrateDefaultBranchesToKeepSettingTest {

private static final String PROPS_TABLE = "properties";
private static final String PATTERN_1 = "(branch|release|llb)-.*";
private static final String PATTERN_2 = "(branch|llb)-.*";
private static final String PATTERN_3 = "llb-.*";

@Rule
public CoreDbTester dbTester = CoreDbTester.createForSchema(MigrateDefaultBranchesToKeepSettingTest.class, "schema.sql");

@Rule
public ExpectedException expectedException = ExpectedException.none();

private MigrateDefaultBranchesToKeepSetting underTest = new MigrateDefaultBranchesToKeepSetting(dbTester.database(), System2.INSTANCE);

@Test
public void migrate_overridden_old_setting() throws SQLException {
setupOverriddenSetting();

underTest.execute();

verifyMigrationOfOverriddenSetting();
}

@Test
public void migration_of_overridden_setting_is_re_entrant() throws SQLException {
setupOverriddenSetting();

underTest.execute();
underTest.execute();

verifyMigrationOfOverriddenSetting();
}

@Test
public void migrate_default_old_setting_on_fresh_install() throws SQLException {
setupDefaultSetting();

underTest.execute();

verifyMigrationOfDefaultSetting("master,develop,trunk");
}

@Test
public void migrate_default_old_setting_on_existing_install() throws SQLException {
setupDefaultSetting();
insertProject();

underTest.execute();

verifyMigrationOfDefaultSetting("master,develop,trunk,branch-.*,release-.*");
}

@Test
public void migration_of_default_old_setting_is_re_entrant() throws SQLException {
setupDefaultSetting();

underTest.execute();
underTest.execute();

verifyMigrationOfDefaultSetting("master,develop,trunk");
}

private void setupOverriddenSetting() {
insertProperty(1, "some.key", "some.value", 1001L);
insertProperty(2, "sonar.branch.longLivedBranches.regex", PATTERN_1, 1001L);
insertProperty(3, "some.other.key", "some.other.value", 1001L);
insertProperty(4, "sonar.branch.longLivedBranches.regex", PATTERN_2, 1002L);
insertProperty(5, "some.other.key", "some.other.value", null);
insertProperty(6, "sonar.branch.longLivedBranches.regex", PATTERN_3, null);
}

private void setupDefaultSetting() {
insertProperty(1, "some.key", "some.value", 1001L);
insertProperty(3, "some.other.key", "some.other.value", 1001L);
insertProperty(5, "some.other.key", "some.other.value", null);
}

private void verifyMigrationOfOverriddenSetting() {
assertThat(dbTester.countRowsOfTable(PROPS_TABLE)).isEqualTo(9);
assertThat(dbTester.countSql("select count(*) from " + PROPS_TABLE + " where prop_key = 'sonar.branch.longLivedBranches.regex'")).isEqualTo(3);
assertThat(dbTester.countSql("select count(*) from " + PROPS_TABLE + " where prop_key = 'sonar.dbcleaner.branchesToKeepWhenInactive'")).isEqualTo(3);
assertThat(dbTester.select("select resource_id, text_value from " + PROPS_TABLE + " where prop_key = 'sonar.dbcleaner.branchesToKeepWhenInactive'")
.stream()
.map(e -> new Tuple(e.get("TEXT_VALUE"), e.get("RESOURCE_ID")))
.collect(Collectors.toList()))
.containsExactlyInAnyOrder(
new Tuple(PATTERN_1, 1001L),
new Tuple(PATTERN_2, 1002L),
new Tuple(PATTERN_3, null));
}

private void verifyMigrationOfDefaultSetting(String expectedValue) {
assertThat(dbTester.countRowsOfTable(PROPS_TABLE)).isEqualTo(4);
assertThat(dbTester.countSql("select count(*) from " + PROPS_TABLE + " where prop_key = 'sonar.branch.longLivedBranches.regex'")).isEqualTo(0);
assertThat(dbTester.countSql("select count(*) from " + PROPS_TABLE + " where prop_key = 'sonar.dbcleaner.branchesToKeepWhenInactive'")).isEqualTo(1);
assertThat(dbTester.select("select resource_id, text_value from " + PROPS_TABLE + " where prop_key = 'sonar.dbcleaner.branchesToKeepWhenInactive'")
.stream()
.map(e -> new Tuple(e.get("TEXT_VALUE"), e.get("RESOURCE_ID")))
.collect(Collectors.toList()))
.containsExactly(new Tuple(expectedValue, null));
}

private void insertProperty(int id, String key, String value, @Nullable Long resourceId) {
dbTester.executeInsert(
PROPS_TABLE,
"ID", id,
"PROP_KEY", key,
"RESOURCE_ID", resourceId,
"USER_ID", null,
"IS_EMPTY", false,
"TEXT_VALUE", value,
"CLOB_VALUE", null,
"CREATED_AT", System2.INSTANCE.now());
}

private void insertProject() {
String uuid = Uuids.createFast();
dbTester.executeInsert("PROJECTS",
"ORGANIZATION_UUID", "default-org",
"KEE", uuid + "-key",
"UUID", uuid,
"PROJECT_UUID", uuid,
"main_branch_project_uuid", uuid,
"UUID_PATH", ".",
"ROOT_UUID", uuid,
"PRIVATE", "true",
"qualifier", "TRK",
"scope", "PRJ");
}
}

+ 109
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/PopulateExcludeBranchFromPurgeColumnTest.java Bestand weergeven

@@ -0,0 +1,109 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.platform.db.migration.version.v81;

import java.sql.SQLException;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.db.CoreDbTester;

import static org.assertj.core.api.Assertions.assertThat;

public class PopulateExcludeBranchFromPurgeColumnTest {

private static final String TABLE = "PROJECT_BRANCHES";

private static final String PROJECT_1_UUID = "1a724f54-c2a4-4d36-b59c-61026f178613";
private static final String PROJECT_2_UUID = "cc69ccb8-434a-489b-abd6-6a80371f64ff";

private static final String MAIN_BRANCH_1 = "8a9789c8-7aee-4aa6-9cb7-407137935ac3";
private static final String LONG_BRANCH_1 = "69fdfc19-491c-4ed9-bcac-ef04e0f6cdc6";
private static final String SHORT_BRANCH_1 = "f7a6d247-1790-40f8-8591-a0cc39d05ecb";
private static final String PR_1 = "d65466bf-271c-4f9f-ac7a-72add44848c0";

private static final String MAIN_BRANCH_2 = "cdadf128-7bdb-4589-982d-62445d46ae1b";
private static final String LONG_BRANCH_2 = "60bf6fa8-3ecc-4ba6-ad8d-991ea7c7f9cb";
private static final String SHORT_BRANCH_2 = "ce5632ed-462e-4384-98b6-1773a7bbfe53";
private static final String PR_2 = "5897f7d0-d34f-4558-b9c5-a7eb7a5c4b69";

@Rule
public CoreDbTester dbTester = CoreDbTester.createForSchema(PopulateExcludeBranchFromPurgeColumnTest.class, "schema.sql");

@Rule
public ExpectedException expectedException = ExpectedException.none();

private PopulateExcludeBranchFromPurgeColumn underTest = new PopulateExcludeBranchFromPurgeColumn(dbTester.database(), System2.INSTANCE);

@Before
public void setup() {
insertBranch(MAIN_BRANCH_1, PROJECT_1_UUID, "master", "BRANCH", "LONG");
insertBranch(LONG_BRANCH_1, PROJECT_1_UUID, "release-1", "BRANCH", "LONG");
insertBranch(SHORT_BRANCH_1, PROJECT_1_UUID, "feature/foo", "BRANCH", "SHORT");
insertBranch(PR_1, PROJECT_1_UUID, "feature/feature-1", "PULL_REQUEST", "PULL_REQUEST");

insertBranch(MAIN_BRANCH_2, PROJECT_2_UUID, "trunk", "BRANCH", "LONG");
insertBranch(LONG_BRANCH_2, PROJECT_2_UUID, "branch-1", "BRANCH", "LONG");
insertBranch(SHORT_BRANCH_2, PROJECT_2_UUID, "feature/bar", "BRANCH", "SHORT");
insertBranch(PR_2, PROJECT_2_UUID, "feature/feature-2", "PULL_REQUEST", "PULL_REQUEST");
}

@Test
public void execute_migration() throws SQLException {
underTest.execute();

verifyMigrationResult();
}

@Test
public void migration_is_re_entrant() throws SQLException {
underTest.execute();
underTest.execute();

verifyMigrationResult();
}

private void verifyMigrationResult() {
assertThat(dbTester.select("select UUID from " + TABLE + " where EXCLUDE_FROM_PURGE = true")
.stream()
.map(e -> e.get("UUID"))
.collect(Collectors.toList())).containsExactlyInAnyOrder(MAIN_BRANCH_1, LONG_BRANCH_1, MAIN_BRANCH_2, LONG_BRANCH_2);
assertThat(dbTester.select("select UUID from " + TABLE + " where EXCLUDE_FROM_PURGE = false")
.stream()
.map(e -> e.get("UUID"))
.collect(Collectors.toList())).containsExactlyInAnyOrder(SHORT_BRANCH_1, SHORT_BRANCH_2, PR_1, PR_2);
}

private void insertBranch(String uuid, String projectUuid, String key, String keyType, String branchType) {
dbTester.executeInsert(
TABLE,
"UUID", uuid,
"PROJECT_UUID", projectUuid,
"KEE", key,
"BRANCH_TYPE", branchType,
"KEY_TYPE", keyType,
"MERGE_BRANCH_UUID", null,
"CREATED_AT", System2.INSTANCE.now(),
"UPDATED_AT", System2.INSTANCE.now());
}
}

+ 13
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v80/MakeExcludeBranchFromPurgeColumnNotNullableTest/schema.sql Bestand weergeven

@@ -0,0 +1,13 @@
CREATE TABLE PROJECT_BRANCHES(
UUID VARCHAR(50) NOT NULL,
PROJECT_UUID VARCHAR(50) NOT NULL,
KEE VARCHAR(255) NOT NULL,
BRANCH_TYPE VARCHAR(12),
MERGE_BRANCH_UUID VARCHAR(50),
KEY_TYPE VARCHAR(12) NOT NULL,
PULL_REQUEST_BINARY BLOB,
MANUAL_BASELINE_ANALYSIS_UUID VARCHAR(40),
CREATED_AT BIGINT NOT NULL,
UPDATED_AT BIGINT NOT NULL,
EXCLUDE_FROM_PURGE BOOLEAN
);

+ 12
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/AddExcludeBranchFromPurgeColumnTest/schema.sql Bestand weergeven

@@ -0,0 +1,12 @@
CREATE TABLE PROJECT_BRANCHES(
UUID VARCHAR(50) NOT NULL,
PROJECT_UUID VARCHAR(50) NOT NULL,
KEE VARCHAR(255) NOT NULL,
BRANCH_TYPE VARCHAR(12),
MERGE_BRANCH_UUID VARCHAR(50),
KEY_TYPE VARCHAR(12) NOT NULL,
PULL_REQUEST_BINARY BLOB,
MANUAL_BASELINE_ANALYSIS_UUID VARCHAR(40),
CREATED_AT BIGINT NOT NULL,
UPDATED_AT BIGINT NOT NULL
);

+ 11
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/MigrateDefaultBranchesToKeepSettingTest/schema.sql Bestand weergeven

@@ -0,0 +1,11 @@
CREATE TABLE "PROPERTIES" (
"ID" INTEGER NOT NULL AUTO_INCREMENT (1,1),
"PROP_KEY" VARCHAR(512) NOT NULL,
"RESOURCE_ID" INTEGER,
"USER_ID" INTEGER,
"IS_EMPTY" BOOLEAN NOT NULL,
"TEXT_VALUE" VARCHAR(4000),
"CLOB_VALUE" CLOB,
"CREATED_AT" BIGINT
);
CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY");

+ 13
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/PopulateExcludeBranchFromPurgeColumnTest/schema.sql Bestand weergeven

@@ -0,0 +1,13 @@
CREATE TABLE PROJECT_BRANCHES(
UUID VARCHAR(50) NOT NULL,
PROJECT_UUID VARCHAR(50) NOT NULL,
KEE VARCHAR(255) NOT NULL,
BRANCH_TYPE VARCHAR(12),
MERGE_BRANCH_UUID VARCHAR(50),
KEY_TYPE VARCHAR(12) NOT NULL,
PULL_REQUEST_BINARY BLOB,
MANUAL_BASELINE_ANALYSIS_UUID VARCHAR(40),
CREATED_AT BIGINT NOT NULL,
UPDATED_AT BIGINT NOT NULL,
EXCLUDE_FROM_PURGE BOOLEAN DEFAULT FALSE NOT NULL
);

+ 1
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/BranchWsModule.java Bestand weergeven

@@ -28,6 +28,7 @@ public class BranchWsModule extends Module {
ListAction.class,
DeleteAction.class,
RenameAction.class,
SetAutomaticDeletionProtectionAction.class,
BranchesWs.class);
}
}

+ 2
- 2
server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/BranchesWs.java Bestand weergeven

@@ -54,8 +54,8 @@ public class BranchesWs implements WebService {
static void addBranchParam(NewAction action) {
action
.createParam(PARAM_BRANCH)
.setDescription("Name of the branch")
.setExampleValue("branch1")
.setDescription("Branch key")
.setExampleValue("feature/my_branch")
.setRequired(true);
}


+ 1
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/ListAction.java Bestand weergeven

@@ -141,6 +141,7 @@ public class ListAction implements BranchWsAction {
ofNullable(branchKey).ifPresent(builder::setName);
builder.setIsMain(branch.isMain());
builder.setType(Common.BranchType.valueOf(branch.getBranchType().name()));
builder.setExcludedFromPurge(branch.isExcludeFromPurge());
return builder;
}


+ 2
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/ProjectBranchesParameters.java Bestand weergeven

@@ -27,12 +27,14 @@ public class ProjectBranchesParameters {
public static final String ACTION_LIST = "list";
public static final String ACTION_DELETE = "delete";
public static final String ACTION_RENAME = "rename";
public static final String ACTION_SET_AUTOMATIC_DELETION_PROTECTION = "set_automatic_deletion_protection";

// parameters
public static final String PARAM_PROJECT = "project";
public static final String PARAM_COMPONENT = "component";
public static final String PARAM_BRANCH = "branch";
public static final String PARAM_NAME = "name";
public static final String PARAM_VALUE = "value";

private ProjectBranchesParameters() {
// static utility class

+ 98
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionAction.java Bestand weergeven

@@ -0,0 +1,98 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.branch.ws;

import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static org.sonar.server.branch.ws.BranchesWs.addBranchParam;
import static org.sonar.server.branch.ws.BranchesWs.addProjectParam;
import static org.sonar.server.branch.ws.ProjectBranchesParameters.ACTION_SET_AUTOMATIC_DELETION_PROTECTION;
import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_BRANCH;
import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_PROJECT;
import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_VALUE;

public class SetAutomaticDeletionProtectionAction implements BranchWsAction {

private final DbClient dbClient;
private final UserSession userSession;
private final ComponentFinder componentFinder;

public SetAutomaticDeletionProtectionAction(DbClient dbClient, UserSession userSession, ComponentFinder componentFinder) {
this.dbClient = dbClient;
this.userSession = userSession;
this.componentFinder = componentFinder;
}

@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction(ACTION_SET_AUTOMATIC_DELETION_PROTECTION)
.setSince("8.1")
.setDescription("Protect a specific branch from automatic deletion. Protection can't be disabled for the main branch.<br/>"
+ "Requires 'Administer' permission on the specified project.")
.setPost(true)
.setHandler(this);

addProjectParam(action);
addBranchParam(action);
action.createParam(PARAM_VALUE)
.setRequired(true)
.setBooleanPossibleValues()
.setDescription("Sets whether the branch should be protected from automatic deletion when it hasn't been analyzed for a set period of time.")
.setExampleValue("true");
}

@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkLoggedIn();
String projectKey = request.mandatoryParam(PARAM_PROJECT);
String branchKey = request.mandatoryParam(PARAM_BRANCH);
boolean excludeFromPurge = request.mandatoryParamAsBoolean(PARAM_VALUE);

try (DbSession dbSession = dbClient.openSession(false)) {
ComponentDto project = componentFinder.getRootComponentByUuidOrKey(dbSession, null, projectKey);
checkPermission(project);

BranchDto branch = dbClient.branchDao().selectByBranchKey(dbSession, project.uuid(), branchKey)
.orElseThrow(() -> new NotFoundException(format("Branch '%s' not found for project '%s'", branchKey, projectKey)));
checkArgument(!branch.isMain() || excludeFromPurge, "Main branch of the project is always excluded from automatic deletion.");

dbClient.branchDao().updateExcludeFromPurge(dbSession, branch.getUuid(), excludeFromPurge);
dbSession.commit();
response.noContent();
}

}

private void checkPermission(ComponentDto project) {
userSession.checkComponentPermission(UserRole.ADMIN, project);
}
}

+ 4
- 2
server/sonar-webserver-webapi/src/main/resources/org/sonar/server/branch/ws/list-example.json Bestand weergeven

@@ -7,7 +7,8 @@
"status": {
"qualityGateStatus": "OK"
},
"analysisDate": "2017-04-03T13:37:00+0100"
"analysisDate": "2017-04-03T13:37:00+0100",
"excludedFromPurge": false
},
{
"name": "master",
@@ -16,7 +17,8 @@
"status": {
"qualityGateStatus": "ERROR"
},
"analysisDate": "2017-04-01T01:15:42+0100"
"analysisDate": "2017-04-01T01:15:42+0100",
"excludedFromPurge": false
}
]
}

+ 1
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/BranchWsModuleTest.java Bestand weergeven

@@ -30,6 +30,6 @@ public class BranchWsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new BranchWsModule().configure(container);
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5);
}
}

+ 208
- 0
server/sonar-webserver-webapi/src/test/java/org/sonar/server/branch/ws/SetAutomaticDeletionProtectionActionTest.java Bestand weergeven

@@ -0,0 +1,208 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.branch.ws;

import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbTester;
import org.sonar.db.component.BranchDto;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.resources.Qualifiers.PROJECT;

public class SetAutomaticDeletionProtectionActionTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();

private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(PROJECT);
private ComponentFinder componentFinder = new ComponentFinder(db.getDbClient(), resourceTypes);
private WsActionTester tester = new WsActionTester(new SetAutomaticDeletionProtectionAction(db.getDbClient(), userSession, componentFinder));

@Test
public void test_definition() {
WebService.Action definition = tester.getDef();
assertThat(definition.key()).isEqualTo("set_automatic_deletion_protection");
assertThat(definition.isPost()).isTrue();
assertThat(definition.isInternal()).isFalse();
assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project", "branch", "value");
assertThat(definition.since()).isEqualTo("8.1");
}

@Test
public void fail_if_missing_project_parameter() {
userSession.logIn();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The 'project' parameter is missing");

tester.newRequest().execute();
}

@Test
public void fail_if_missing_branch_parameter() {
userSession.logIn();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The 'branch' parameter is missing");

tester.newRequest()
.setParam("project", "projectName")
.execute();
}

@Test
public void fail_if_missing_value_parameter() {
userSession.logIn();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("The 'value' parameter is missing");

tester.newRequest()
.setParam("project", "projectName")
.setParam("branch", "foobar")
.execute();
}

@Test
public void fail_if_not_logged_in() {
expectedException.expect(UnauthorizedException.class);
expectedException.expectMessage("Authentication is required");

tester.newRequest().execute();
}

@Test
public void fail_if_no_administer_permission() {
userSession.logIn();
ComponentDto project = db.components().insertMainBranch();

expectedException.expect(ForbiddenException.class);
expectedException.expectMessage("Insufficient privileges");

tester.newRequest()
.setParam("project", project.getKey())
.setParam("branch", "branch1")
.setParam("value", "true")
.execute();
}

@Test
public void fail_when_attempting_to_set_main_branch_as_included_in_purge() {
userSession.logIn();
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch1").setExcludeFromPurge(false));
userSession.addProjectPermission(UserRole.ADMIN, project);
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Main branch of the project is always excluded from automatic deletion.");

tester.newRequest()
.setParam("project", project.getKey())
.setParam("branch", "master")
.setParam("value", "false")
.execute();
}

@Test
public void set_purge_exclusion() {
userSession.logIn();
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch1").setExcludeFromPurge(false));
userSession.addProjectPermission(UserRole.ADMIN, project);

tester.newRequest()
.setParam("project", project.getKey())
.setParam("branch", "branch1")
.setParam("value", "true")
.execute();

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();

Optional<BranchDto> branchDto = db.getDbClient().branchDao().selectByUuid(db.getSession(), branch.uuid());
assertThat(branchDto.get().getKey()).isEqualTo("branch1");
assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
}

@Test
public void fail_on_non_boolean_value_parameter() {
userSession.logIn();
ComponentDto project = db.components().insertMainBranch();

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Value of parameter 'value' (foobar) must be one of: [true, false, yes, no]");

tester.newRequest()
.setParam("project", project.getKey())
.setParam("branch", "branch1")
.setParam("value", "foobar")
.execute();
}

@Test
public void fail_if_project_does_not_exist() {
userSession.logIn();

expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Project key 'foo' not found");

tester.newRequest()
.setParam("project", "foo")
.setParam("branch", "branch1")
.setParam("value", "true")
.execute();
}

@Test
public void fail_if_branch_does_not_exist() {
userSession.logIn();
ComponentDto project = db.components().insertMainBranch();
userSession.addProjectPermission(UserRole.ADMIN, project);

expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Branch 'branch1' not found for project '" + project.getKey() + "'");

tester.newRequest()
.setParam("project", project.getKey())
.setParam("branch", "branch1")
.setParam("value", "true")
.execute();
}
}

+ 2
- 1
sonar-core/src/main/java/org/sonar/core/config/PurgeConstants.java Bestand weergeven

@@ -27,5 +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_SHORT_LIVING_BRANCHES = "sonar.dbcleaner.daysBeforeDeletingInactiveShortLivingBranches";
String DAYS_BEFORE_DELETING_INACTIVE_BRANCHES = "sonar.dbcleaner.daysBeforeDeletingInactiveBranches";
String BRANCHES_TO_KEEP_WHEN_INACTIVE = "sonar.dbcleaner.branchesToKeepWhenInactive";
}

+ 13
- 15
sonar-core/src/main/java/org/sonar/core/config/PurgeProperties.java Bestand weergeven

@@ -41,8 +41,8 @@ public final class PurgeProperties {
+ "the DbCleaner keeps the most recent one and fully deletes the other ones.")
.type(PropertyType.INTEGER)
.onQualifiers(Qualifiers.PROJECT)
.category(CoreProperties.CATEGORY_GENERAL)
.subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
.category(CoreProperties.CATEGORY_HOUSEKEEPING)
.subCategory(CoreProperties.SUBCATEGORY_GENERAL)
.index(1)
.build(),

@@ -53,8 +53,8 @@ public final class PurgeProperties {
+ "the DbCleaner keeps the most recent one and fully deletes the other ones")
.type(PropertyType.INTEGER)
.onQualifiers(Qualifiers.PROJECT)
.category(CoreProperties.CATEGORY_GENERAL)
.subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
.category(CoreProperties.CATEGORY_HOUSEKEEPING)
.subCategory(CoreProperties.SUBCATEGORY_GENERAL)
.index(2)
.build(),

@@ -65,20 +65,19 @@ public final class PurgeProperties {
+ "the DbCleaner keeps the most recent one and fully deletes the other ones.")
.type(PropertyType.INTEGER)
.onQualifiers(Qualifiers.PROJECT)
.category(CoreProperties.CATEGORY_GENERAL)
.subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
.category(CoreProperties.CATEGORY_HOUSEKEEPING)
.subCategory(CoreProperties.SUBCATEGORY_GENERAL)
.index(3)
.build(),


PropertyDefinition.builder(PurgeConstants.WEEKS_BEFORE_KEEPING_ONLY_ANALYSES_WITH_VERSION)
.defaultValue("104")
.name("Keep only analyses with a version event after")
.description("After this number of weeks, the DbCleaner keeps only analyses with a version event associated.")
.type(PropertyType.INTEGER)
.onQualifiers(Qualifiers.PROJECT)
.category(CoreProperties.CATEGORY_GENERAL)
.subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
.category(CoreProperties.CATEGORY_HOUSEKEEPING)
.subCategory(CoreProperties.SUBCATEGORY_GENERAL)
.index(4)
.build(),

@@ -88,8 +87,8 @@ public final class PurgeProperties {
.description("After this number of weeks, all analyses are fully deleted.")
.type(PropertyType.INTEGER)
.onQualifiers(Qualifiers.PROJECT)
.category(CoreProperties.CATEGORY_GENERAL)
.subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
.category(CoreProperties.CATEGORY_HOUSEKEEPING)
.subCategory(CoreProperties.SUBCATEGORY_GENERAL)
.index(5)
.build(),

@@ -99,10 +98,9 @@ public final class PurgeProperties {
.description("Issues that have been closed for more than this number of days will be deleted.")
.type(PropertyType.INTEGER)
.onQualifiers(Qualifiers.PROJECT)
.category(CoreProperties.CATEGORY_GENERAL)
.subCategory(CoreProperties.SUBCATEGORY_DATABASE_CLEANER)
.category(CoreProperties.CATEGORY_HOUSEKEEPING)
.subCategory(CoreProperties.SUBCATEGORY_GENERAL)
.index(6)
.build()
);
.build());
}
}

+ 3
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties Bestand weergeven

@@ -1034,6 +1034,9 @@ property.error.notFloat=Not a floating point number
property.error.notRegexp=Not a valid Java regular expression
property.error.notInOptions=Not a valid option
property.category.scm=SCM
property.category.housekeeping=Housekeeping
property.category.housekeeping.general=General
property.category.housekeeping.branchesAndPullRequests=Branches and Pull Requests
property.sonar.branch.longLivedBranches.regex.description=Regular expression used to detect whether a branch is a long living branch (as opposed to short living branch), based on its name. This applies only during first analysis, the type of a branch cannot be changed later.



+ 13
- 1
sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java Bestand weergeven

@@ -41,7 +41,9 @@ public interface CoreProperties {

/**
* @since 4.0
* @deprecated since 8.1. Database cleaning now has a dedicated category {@link CoreProperties#CATEGORY_HOUSEKEEPING}.
*/
@Deprecated
String SUBCATEGORY_DATABASE_CLEANER = "databaseCleaner";

/**
@@ -54,10 +56,20 @@ public interface CoreProperties {
*/
String SUBCATEGORY_DUPLICATIONS = "duplications";

/**
* @since 8.1
*/
String CATEGORY_HOUSEKEEPING = "housekeeping";

/**
* @since 6.6
*/
String SUBCATEGORY_BRANCHES = "Branches";
String SUBCATEGORY_BRANCHES_AND_PULL_REQUESTS = "branchesAndPullRequests";

/**
* @since 8.1
*/
String SUBCATEGORY_GENERAL = "general";

/**
* @since 4.0

+ 1
- 0
sonar-ws/src/main/protobuf/ws-projectbranches.proto Bestand weergeven

@@ -44,6 +44,7 @@ message Branch {
optional Status status = 5;
optional bool isOrphan = 6;
optional string analysisDate = 7;
optional bool excludedFromPurge = 8;
}

message Status {

Laden…
Annuleren
Opslaan