]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13579 Ensure issue tracking between new file on Pull Request and original file...
authorKlaudio Sinani <klaudio.sinani@sonarsource.com>
Fri, 21 Oct 2022 11:57:52 +0000 (13:57 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 26 Oct 2022 20:03:10 +0000 (20:03 +0000)
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/MovedFilesRepository.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepository.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryImpl.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/filemove/PullRequestFileMoveDetectionStep.java
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerTargetBranchInputFactory.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/MutableMovedFilesRepositoryRule.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IntegrateIssuesVisitorTest.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerTargetBranchInputFactoryTest.java

index 22eb662a9970b5487b888de88350ba7992a224b2..b541d75009051a6b7616d8bdd87a7fb080d1b49b 100644 (file)
@@ -34,6 +34,14 @@ public interface MovedFilesRepository {
    */
   Optional<OriginalFile> getOriginalFile(Component file);
 
+  /**
+   * The original file for the specified component if it was registered as a moved file inside the scope of a Pull Request.
+   * <p>
+   * Calling this method with a Component which is not a file, will always return {@link Optional#empty()}.
+   * </p>
+   */
+  Optional<OriginalFile> getOriginalPullRequestFile(Component file);
+
   final class OriginalFile {
     private final String uuid;
     private final String key;
index f357bdf3ea5c250ac68fd2374178d7c11b519648..3be81900373fafeb404789a5e2f21ec7d2d4200e 100644 (file)
@@ -29,4 +29,12 @@ public interface MutableMovedFilesRepository extends MovedFilesRepository {
    * @throws IllegalStateException if {@code file} already has an original file
    */
   void setOriginalFile(Component file, OriginalFile originalFile);
+
+  /**
+   * Registers the original file for the specified file that has been renamed/moved inside the scope of a Pull Request.
+   *
+   * @throws IllegalArgumentException if {@code file} type is not {@link Component.Type#FILE}
+   * @throws IllegalStateException if {@code file} already has an original file
+   */
+  void setOriginalPullRequestFile(Component file, OriginalFile originalFile);
 }
index b05ba83cf86b9250c54b7d6c47ef24d2e50236f0..b93e7e26e19d344cfd8aedd2453283e8a5b4d2f5 100644 (file)
@@ -30,24 +30,46 @@ import static java.util.Objects.requireNonNull;
 
 public class MutableMovedFilesRepositoryImpl implements MutableMovedFilesRepository {
   private final Map<String, OriginalFile> originalFiles = new HashMap<>();
+  private final Map<String, OriginalFile> originalPullRequestFiles = new HashMap<>();
 
   @Override
   public void setOriginalFile(Component file, OriginalFile originalFile) {
+    storeOriginalFileInCache(originalFiles, file, originalFile);
+  }
+
+  @Override
+  public void setOriginalPullRequestFile(Component file, OriginalFile originalFile) {
+    storeOriginalFileInCache(originalPullRequestFiles, file, originalFile);
+  }
+
+  @Override
+  public Optional<OriginalFile> getOriginalFile(Component file) {
+    return retrieveOriginalFileFromCache(originalFiles, file);
+  }
+
+  @Override
+  public Optional<OriginalFile> getOriginalPullRequestFile(Component file) {
+    return retrieveOriginalFileFromCache(originalPullRequestFiles, file);
+  }
+
+  private void storeOriginalFileInCache(Map<String, OriginalFile> originalFiles, Component file, OriginalFile originalFile) {
     requireNonNull(file, "file can't be null");
     requireNonNull(originalFile, "originalFile can't be null");
     checkArgument(file.getType() == Component.Type.FILE, "file must be of type FILE");
 
     OriginalFile existingOriginalFile = originalFiles.get(file.getKey());
+
     checkState(existingOriginalFile == null || existingOriginalFile.equals(originalFile),
       "Original file %s already registered for file %s. Unable to register %s.", existingOriginalFile, file, originalFile);
+
     if (existingOriginalFile == null) {
       originalFiles.put(file.getKey(), originalFile);
     }
   }
 
-  @Override
-  public Optional<OriginalFile> getOriginalFile(Component file) {
+  private Optional<OriginalFile> retrieveOriginalFileFromCache(Map<String, OriginalFile> originalFiles, Component file) {
     requireNonNull(file, "file can't be null");
+
     if (file.getType() != Component.Type.FILE) {
       return Optional.empty();
     }
index 77f172f8763ab623b5bf3e625e1d058b811d2331..3a3197fdf3fcf8a19e42e14ec9a339129fde6013 100644 (file)
@@ -26,7 +26,9 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import javax.annotation.concurrent.Immutable;
 import org.apache.ibatis.session.ResultHandler;
@@ -39,6 +41,7 @@ import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
 import org.sonar.ce.task.projectanalysis.component.DepthTraversalTypeAwareCrawler;
 import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
 import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
+import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository.OriginalFile;
 import org.sonar.ce.task.step.ComputationStep;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
@@ -102,17 +105,18 @@ public class PullRequestFileMoveDetectionStep implements ComputationStep {
     Map<String, Component> newlyAddedFilesByUuid = getNewlyAddedFilesByUuid(reportFilesByUuid, targetBranchDbFilesByUuid);
     context.getStatistics().add("addedFiles", newlyAddedFilesByUuid.size());
 
-    // Do we need to register the moved file in the moved files repo and use the data in the related steps/visitors?
-//    registerMovedFiles(movedFilesByUuid, targetBranchDbFilesByUuid);
+    registerMovedFiles(movedFilesByUuid.values(), targetBranchDbFilesByUuid.values());
     registerNewlyAddedFiles(newlyAddedFilesByUuid);
   }
 
-  private void registerMovedFiles(Map<String, Component> movedFilesByUuid, Map<String, DbComponent> dbFilesByUuid) {
-    movedFilesByUuid
-      .forEach((movedFileUuid, movedFile) -> {
-        DbComponent oldFile = getOldFile(dbFilesByUuid.values(), movedFile.getOldName());
-        movedFilesRepository.setOriginalFile(movedFile, toOriginalFile(oldFile));
-      });
+  private void registerMovedFiles(Collection<Component> movedFiles, Collection<DbComponent> dbFiles) {
+    movedFiles
+      .forEach(registerMovedFile(dbFiles));
+  }
+
+  private Consumer<Component> registerMovedFile(Collection<DbComponent> dbFiles) {
+    return movedFile -> retrieveDbFile(dbFiles, movedFile)
+        .ifPresent(dbFile -> movedFilesRepository.setOriginalPullRequestFile(movedFile, toOriginalFile(dbFile)));
   }
 
   private void registerNewlyAddedFiles(Map<String, Component> newAddedFilesByUuid) {
@@ -139,12 +143,11 @@ public class PullRequestFileMoveDetectionStep implements ComputationStep {
       .collect(toMap(Component::getUuid, Function.identity()));
   }
 
-  private DbComponent getOldFile(Collection<DbComponent> dbFiles, String oldFilePath) {
+  private Optional<DbComponent> retrieveDbFile(Collection<DbComponent> dbFiles, Component file) {
     return dbFiles
       .stream()
-      .filter(file -> file.getPath().equals(oldFilePath))
-      .findFirst()
-      .get();
+      .filter(dbFile -> dbFile.getPath().equals(file.getOldName()))
+      .findFirst();
   }
 
   public Set<String> difference(Set<String> set1, Set<String> set2) {
@@ -166,7 +169,7 @@ public class PullRequestFileMoveDetectionStep implements ComputationStep {
   }
 
   private List<DbComponent> getTargetBranchDbFiles(DbSession dbSession, String targetBranchUuid) {
-     List<DbComponent> files = new LinkedList();
+     List<DbComponent> files = new LinkedList<>();
 
     ResultHandler<FileMoveRowDto> storeFileMove = resultContext -> {
       FileMoveRowDto row = resultContext.getResultObject();
@@ -198,8 +201,8 @@ public class PullRequestFileMoveDetectionStep implements ComputationStep {
     return builder.build();
   }
 
-  private static MovedFilesRepository.OriginalFile toOriginalFile(DbComponent dbComponent) {
-    return new MovedFilesRepository.OriginalFile(dbComponent.getUuid(), dbComponent.getKey());
+  private static OriginalFile toOriginalFile(DbComponent dbComponent) {
+    return new OriginalFile(dbComponent.getUuid(), dbComponent.getKey());
   }
 
   @Immutable
index 1e28a40b382858015db93edf1a3e0c3f8e3713d5..a1f513c8371a741986a4ff84ebd0e610db8cd660 100644 (file)
@@ -21,8 +21,11 @@ package org.sonar.ce.task.projectanalysis.issue;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import javax.annotation.Nullable;
 import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
+import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository.OriginalFile;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.tracking.Input;
 import org.sonar.core.issue.tracking.LazyInput;
@@ -36,12 +39,14 @@ public class TrackerTargetBranchInputFactory {
   private final ComponentIssuesLoader componentIssuesLoader;
   private final DbClient dbClient;
   private final TargetBranchComponentUuids targetBranchComponentUuids;
+  private final MovedFilesRepository movedFilesRepository;
 
   public TrackerTargetBranchInputFactory(ComponentIssuesLoader componentIssuesLoader, TargetBranchComponentUuids targetBranchComponentUuids,
-    DbClient dbClient) {
+    DbClient dbClient, MovedFilesRepository movedFilesRepository) {
     this.componentIssuesLoader = componentIssuesLoader;
     this.targetBranchComponentUuids = targetBranchComponentUuids;
     this.dbClient = dbClient;
+    this.movedFilesRepository = movedFilesRepository;
     // TODO detect file moves?
   }
 
@@ -50,10 +55,26 @@ public class TrackerTargetBranchInputFactory {
   }
 
   public Input<DefaultIssue> createForTargetBranch(Component component) {
-    String targetBranchComponentUuid = targetBranchComponentUuids.getTargetBranchComponentUuid(component.getKey());
+    String targetBranchComponentUuid = getTargetBranchComponentUuid(component);
     return new TargetLazyInput(component.getType(), targetBranchComponentUuid);
   }
 
+  private String getTargetBranchComponentUuid(Component component) {
+    Optional<String> targetBranchOriginalComponentUuid = getOriginalComponentUuid(component);
+
+    if (targetBranchOriginalComponentUuid.isPresent()) {
+      return targetBranchComponentUuids.getTargetBranchComponentUuid(targetBranchOriginalComponentUuid.get());
+    }
+
+    return targetBranchComponentUuids.getTargetBranchComponentUuid(component.getKey());
+  }
+
+  private Optional<String> getOriginalComponentUuid(Component component) {
+    return movedFilesRepository
+      .getOriginalPullRequestFile(component)
+      .map(OriginalFile::getKey);
+  }
+
   private class TargetLazyInput extends LazyInput<DefaultIssue> {
     private final Component.Type type;
     private final String targetBranchComponentUuid;
index 0a3831289ea5e61c370422b0cada1c763cb77dd6..de726f775bcc3e272be4abff93e363db065cd4f6 100644 (file)
@@ -49,11 +49,22 @@ public class MutableMovedFilesRepositoryRule extends ExternalResource implements
     this.componentsWithOriginal.add(file);
   }
 
+  @Override
+  public void setOriginalPullRequestFile(Component file, OriginalFile originalFile) {
+    this.delegate.setOriginalPullRequestFile(file, originalFile);
+    this.componentsWithOriginal.add(file);
+  }
+
   @Override
   public Optional<OriginalFile> getOriginalFile(Component file) {
     return this.delegate.getOriginalFile(file);
   }
 
+  @Override
+  public Optional<OriginalFile> getOriginalPullRequestFile(Component file) {
+    return this.delegate.getOriginalPullRequestFile(file);
+  }
+
   public Set<Component> getComponentsWithOriginal() {
     return componentsWithOriginal;
   }
index e4eb4bb9037b8ff1e0579fd7aa64b31fae3dc357..cbc7508b8365b2d80dfe9d56fe0b3d91fa249339 100644 (file)
@@ -154,7 +154,7 @@ public class IntegrateIssuesVisitorTest {
       ruleRepositoryRule, activeRulesHolder);
     TrackerBaseInputFactory baseInputFactory = new TrackerBaseInputFactory(issuesLoader, dbClient, movedFilesRepository, mock(ReportModulesPath.class), analysisMetadataHolder,
       new IssueFieldsSetter(), mock(ComponentsWithUnprocessedIssues.class));
-    TrackerTargetBranchInputFactory targetInputFactory = new TrackerTargetBranchInputFactory(issuesLoader, targetBranchComponentUuids, dbClient);
+    TrackerTargetBranchInputFactory targetInputFactory = new TrackerTargetBranchInputFactory(issuesLoader, targetBranchComponentUuids, dbClient, movedFilesRepository);
     TrackerReferenceBranchInputFactory mergeInputFactory = new TrackerReferenceBranchInputFactory(issuesLoader, mergeBranchComponentsUuids, dbClient);
     ClosedIssuesInputFactory closedIssuesInputFactory = new ClosedIssuesInputFactory(issuesLoader, dbClient, movedFilesRepository);
     tracker = new TrackerExecution(baseInputFactory, closedIssuesInputFactory, new Tracker<>(), issuesLoader, analysisMetadataHolder);
index 5c678fee52a4434559fa2947d9ee193d53ae2467..4e5a5f05dd02f8dad1095c3677f8333591c81588 100644 (file)
@@ -24,6 +24,7 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.filemove.MovedFilesRepository;
 import org.sonar.core.issue.DefaultIssue;
 import org.sonar.core.issue.tracking.Input;
 import org.sonar.db.DbTester;
@@ -43,11 +44,12 @@ public class TrackerTargetBranchInputFactoryTest {
 
   private final ComponentIssuesLoader componentIssuesLoader = mock(ComponentIssuesLoader.class);
   private final TargetBranchComponentUuids targetBranchComponentUuids = mock(TargetBranchComponentUuids.class);
+  private final MovedFilesRepository movedFilesRepository = mock(MovedFilesRepository.class);
   private TrackerTargetBranchInputFactory underTest;
 
   @Before
   public void setUp() {
-    underTest = new TrackerTargetBranchInputFactory(componentIssuesLoader, targetBranchComponentUuids, db.getDbClient());
+    underTest = new TrackerTargetBranchInputFactory(componentIssuesLoader, targetBranchComponentUuids, db.getDbClient(), movedFilesRepository);
   }
 
   @Test