]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-14956 Issues are not automatically closed when component has been removed from DB
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 3 May 2023 13:54:02 +0000 (08:54 -0500)
committersonartech <sonartech@sonarsource.com>
Thu, 4 May 2023 20:03:11 +0000 (20:03 +0000)
server/sonar-db-dao/src/it/java/org/sonar/db/purge/PurgeDaoIT.java
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml

index b636205ca39262f11df16e0dc16e74f8abac23a3..e70f5ab9739c9b721dda420b3be91d6ffde6e33f 100644 (file)
@@ -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();
index 96bd8b20616f0ec33d16db11c7181603b96179ef..c8ae626baa0a8fd257b20cf83bccdfe4babf79c8 100644 (file)
@@ -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<String> 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<String> issueKeys = mapper.selectOldClosedIssueKeys(rootUuid, dateToLong(toDate));
+    deleteIssues(mapper, issueKeys);
+    listener.onIssuesRemoval(rootUuid, issueKeys);
+  }
+
+  private static void deleteIssues(PurgeMapper mapper, Collection<String> 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) {
index f76ceaabd2f9d5022098274ab1362ff94bee4380..66d60bdd6f7ee1bc0563e47dd3e5f8621c687724 100644 (file)
@@ -88,6 +88,8 @@ public interface PurgeMapper {
 
   void deleteIssueChangesByProjectUuid(@Param("projectUuid") String projectUuid);
 
+  List<String> selectBranchOrphanIssues(@Param("branchUuid") String branchUuid);
+
   void deleteNewCodeReferenceIssuesByProjectUuid(@Param("projectUuid") String projectUuid);
 
   List<String> selectOldClosedIssueKeys(@Param("projectUuid") String projectUuid, @Nullable @Param("toDate") Long toDate);
index f554a8e5e9902d5ca1615c62c265fd20f1f7c3a3..1eb0d1f20a4c212ff3442f1dbbc89f2964d6b620 100644 (file)
     </choose>
   </select>
 
+  <select id="selectBranchOrphanIssues" parameterType="map">
+    select i.kee from issues i
+    left outer join components c on i.component_uuid = c.uuid
+    where i.project_uuid = #{branchUuid,jdbcType=VARCHAR} and c.kee is null
+  </select>
+
+
   <select id="selectDisabledComponentsWithoutIssues" resultType="String" parameterType="String">
     SELECT
       p.uuid