From 258ab58f69d7f6e59abe23fe0e7b4f044b2b4bbf Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Wed, 3 May 2023 08:54:02 -0500 Subject: [PATCH] SONAR-14956 Issues are not automatically closed when component has been removed from DB --- .../java/org/sonar/db/purge/PurgeDaoIT.java | 21 +++++++++++++++++++ .../java/org/sonar/db/purge/PurgeDao.java | 13 +++++++++++- .../java/org/sonar/db/purge/PurgeMapper.java | 2 ++ .../org/sonar/db/purge/PurgeMapper.xml | 7 +++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java index b636205ca39..e70f5ab9739 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java @@ -1131,6 +1131,27 @@ public class PurgeDaoIT { .containsOnly(project.uuid(), otherView.uuid(), otherSubView.uuid(), otherProjectCopy.uuid()); } + @Test + public void purge_shouldDeleteOrphanIssues() { + RuleDto rule = db.rules().insert(); + ComponentDto project = db.components().insertPublicProject(); + ComponentDto otherProject = db.components().insertPublicProject(); + ComponentDto dir = db.components().insertComponent(newDirectory(project, "path")); + ComponentDto file = db.components().insertComponent(newFileDto(project, dir)); + + IssueDto issue1 = db.issues().insert(rule, project, file); + IssueDto orphanIssue = db.issues().insert(rule, project, file, issue -> issue.setComponentUuid("nonExisting")); + IssueChangeDto orphanIssueChange = db.issues().insertChange(orphanIssue); + db.issues().insertNewCodeReferenceIssue(orphanIssue); + + underTest.purge(dbSession, newConfigurationWith30Days(system2, project.uuid(), project.uuid()), PurgeListener.EMPTY, new PurgeProfiler()); + db.commit(); + + assertThat(db.countRowsOfTable("issue_changes")).isZero(); + assertThat(db.countRowsOfTable("new_code_reference_issues")).isZero(); + assertThat(db.select("select kee as \"KEE\" from issues")).extracting(i -> i.get("KEE")).containsOnly(issue1.getKey()); + } + @Test public void should_delete_old_closed_issues() { RuleDto rule = db.rules().insert(); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java index 96bd8b20616..c8ae626baa0 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java @@ -67,6 +67,7 @@ public class PurgeDao implements Dao { purgeAnalyses(commands, rootUuid); purgeDisabledComponents(commands, conf, listener); deleteOldClosedIssues(conf, mapper, listener); + deleteOrphanIssues(mapper, rootUuid); purgeOldCeActivities(rootUuid, commands); purgeOldCeScannerContexts(rootUuid, commands); @@ -106,10 +107,21 @@ public class PurgeDao implements Dao { commands.purgeDisabledComponents(rootUuid, conf.getDisabledComponentUuids(), listener); } + private static void deleteOrphanIssues(PurgeMapper mapper, String rootUuid) { + LOG.debug("<- Delete orphan issues"); + List issueKeys = mapper.selectBranchOrphanIssues(rootUuid); + deleteIssues(mapper, issueKeys); + } + private static void deleteOldClosedIssues(PurgeConfiguration conf, PurgeMapper mapper, PurgeListener listener) { Date toDate = conf.maxLiveDateOfClosedIssues(); String rootUuid = conf.rootUuid(); List issueKeys = mapper.selectOldClosedIssueKeys(rootUuid, dateToLong(toDate)); + deleteIssues(mapper, issueKeys); + listener.onIssuesRemoval(rootUuid, issueKeys); + } + + private static void deleteIssues(PurgeMapper mapper, Collection issueKeys) { executeLargeInputs(issueKeys, input -> { mapper.deleteIssueChangesFromIssueKeys(input); return emptyList(); @@ -124,7 +136,6 @@ public class PurgeDao implements Dao { mapper.deleteIssuesFromKeys(input); return emptyList(); }); - listener.onIssuesRemoval(rootUuid, issueKeys); } private static void deleteAbortedAnalyses(String rootUuid, PurgeCommands commands) { diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java index f76ceaabd2f..66d60bdd6f7 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java @@ -88,6 +88,8 @@ public interface PurgeMapper { void deleteIssueChangesByProjectUuid(@Param("projectUuid") String projectUuid); + List selectBranchOrphanIssues(@Param("branchUuid") String branchUuid); + void deleteNewCodeReferenceIssuesByProjectUuid(@Param("projectUuid") String projectUuid); List selectOldClosedIssueKeys(@Param("projectUuid") String projectUuid, @Nullable @Param("toDate") Long toDate); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml index f554a8e5e99..1eb0d1f20a4 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml @@ -317,6 +317,13 @@ + + +