]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10126 add scmPath to ReportAttributes 2914/head
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 15 Dec 2017 14:01:22 +0000 (15:01 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 18 Dec 2017 08:26:36 +0000 (09:26 +0100)
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ReportAttributes.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java

index 0581d636b865bfae4e39bdeadcbee47ccd521186..219919562baefbcb53187b7227ffaa2a65ca0043 100644 (file)
@@ -78,19 +78,21 @@ public class ComponentTreeBuilder {
     this.baseAnalysis = baseAnalysis;
   }
 
-  public Component buildProject(ScannerReport.Component project) {
-    return buildComponent(project, project);
+  public Component buildProject(ScannerReport.Component project, String scmBasePath) {
+    return buildComponent(project, project, trimToNull(scmBasePath));
   }
 
-  private List<Component> buildChildren(ScannerReport.Component component, ScannerReport.Component parentModule) {
+  private List<Component> buildChildren(ScannerReport.Component component, ScannerReport.Component parentModule,
+    String projectScmPath) {
     return component.getChildRefList()
       .stream()
       .map(scannerComponentSupplier::apply)
-      .map(c -> buildComponent(c, parentModule))
+      .map(c -> buildComponent(c, parentModule, projectScmPath))
       .collect(Collectors.toList());
   }
 
-  private ComponentImpl buildComponent(ScannerReport.Component component, ScannerReport.Component closestModule) {
+  private ComponentImpl buildComponent(ScannerReport.Component component, ScannerReport.Component closestModule,
+    @Nullable String scmBasePath) {
     switch (component.getType()) {
       case PROJECT:
         String projectKey = keyGenerator.generateKey(component, null);
@@ -103,10 +105,10 @@ public class ComponentTreeBuilder {
           .setName(nameOfProject(component))
           .setStatus(convertStatus(component.getStatus()))
           .setDescription(trimToNull(component.getDescription()))
-          .setReportAttributes(createAttributesBuilder(component)
+          .setReportAttributes(createAttributesBuilder(component, scmBasePath)
             .setVersion(createProjectVersion(component))
             .build())
-          .addChildren(buildChildren(component, component))
+          .addChildren(buildChildren(component, component, scmBasePath))
           .build();
 
       case MODULE:
@@ -119,8 +121,8 @@ public class ComponentTreeBuilder {
           .setName(nameOfOthers(component, modulePublicKey))
           .setStatus(convertStatus(component.getStatus()))
           .setDescription(trimToNull(component.getDescription()))
-          .setReportAttributes(createAttributesBuilder(component).build())
-          .addChildren(buildChildren(component, component))
+          .setReportAttributes(createAttributesBuilder(component, scmBasePath).build())
+          .addChildren(buildChildren(component, component, scmBasePath))
           .build();
 
       case DIRECTORY:
@@ -134,9 +136,9 @@ public class ComponentTreeBuilder {
           .setName(nameOfOthers(component, publicKey))
           .setStatus(convertStatus(component.getStatus()))
           .setDescription(trimToNull(component.getDescription()))
-          .setReportAttributes(createAttributesBuilder(component).build())
+          .setReportAttributes(createAttributesBuilder(component, scmBasePath).build())
           .setFileAttributes(createFileAttributes(component))
-          .addChildren(buildChildren(component, closestModule))
+          .addChildren(buildChildren(component, closestModule, scmBasePath))
           .build();
 
       default:
@@ -145,7 +147,7 @@ public class ComponentTreeBuilder {
   }
 
   private static Component.Status convertStatus(FileStatus status) {
-    switch(status) {
+    switch (status) {
       case ADDED:
         return Component.Status.ADDED;
       case SAME:
@@ -184,10 +186,22 @@ public class ComponentTreeBuilder {
     return DEFAULT_PROJECT_VERSION;
   }
 
-  private static ReportAttributes.Builder createAttributesBuilder(ScannerReport.Component component) {
+  private static ReportAttributes.Builder createAttributesBuilder(ScannerReport.Component component, @Nullable String scmBasePath) {
     return ReportAttributes.newBuilder(component.getRef())
       .setVersion(trimToNull(component.getVersion()))
-      .setPath(trimToNull(component.getPath()));
+      .setPath(trimToNull(component.getPath()))
+      .setScmPath(computeScmPath(scmBasePath, component.getProjectRelativePath()));
+  }
+
+  @CheckForNull
+  private static String computeScmPath(@Nullable String scmBasePath, String scmRelativePath) {
+    if (scmRelativePath.isEmpty()) {
+      return null;
+    }
+    if (scmBasePath == null) {
+      return scmRelativePath;
+    }
+    return scmBasePath + '/' + scmRelativePath;
   }
 
   @CheckForNull
index 0c7e5db435c1b71ca041973c390537f899a172e0..f560d6852be3f59104bab0aa026c5faa1a758d73 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.computation.task.projectanalysis.component;
 
+import java.util.Optional;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.Immutable;
@@ -33,11 +34,14 @@ public class ReportAttributes {
   private final String version;
   @CheckForNull
   private final String path;
+  @CheckForNull
+  private final String scmPath;
 
   private ReportAttributes(Builder builder) {
     this.ref = builder.ref;
     this.version = builder.version;
     this.path = builder.path;
+    this.scmPath = builder.scmPath;
   }
 
   public static Builder newBuilder(int ref) {
@@ -50,6 +54,8 @@ public class ReportAttributes {
     private String version;
     @CheckForNull
     private String path;
+    @CheckForNull
+    private String scmPath;
 
     private Builder(int ref) {
       this.ref = ref;
@@ -65,6 +71,11 @@ public class ReportAttributes {
       return this;
     }
 
+    public Builder setScmPath(@Nullable String scmPath) {
+      this.scmPath = scmPath;
+      return this;
+    }
+
     public ReportAttributes build() {
       return new ReportAttributes(this);
     }
@@ -93,12 +104,23 @@ public class ReportAttributes {
     return path;
   }
 
+  /**
+   * The path of the component relative the SCM root the project is part of.
+   * <p>
+   * Can be {@link Optional#empty() empty} if project is not version controlled,
+   * otherwise should be non {@link Optional#isPresent() non empty} for all components.
+   */
+  public Optional<String> getScmPath() {
+    return Optional.ofNullable(scmPath);
+  }
+
   @Override
   public String toString() {
     return "ReportAttributes{" +
       "ref=" + ref +
       ", version='" + version + '\'' +
       ", path='" + path + '\'' +
+      ", scmPath='" + scmPath + '\'' +
       '}';
   }
 }
index fffb6cb5db0f784c4f9b13515bbddaeb2e847120..4af8a4019e1a74fe03cabc19b712f7bec5ddeec8 100644 (file)
@@ -82,7 +82,8 @@ public class BuildComponentTreeStep implements ComputationStep {
         reportReader::readComponent,
         analysisMetadataHolder.getProject(),
         baseAnalysis);
-      Component project = builder.buildProject(reportProject);
+      String relativePathFromScmRoot = reportReader.readMetadata().getRelativePathFromScmRoot();
+      Component project = builder.buildProject(reportProject, relativePathFromScmRoot);
 
       treeRootHolder.setRoot(project);
       analysisMetadataHolder.setBaseAnalysis(toAnalysis(baseAnalysis));
index 663125a229ece20358d2de9c348a9f811479c270..baddf91b3af16bacdac96b1443dc9e180fce0b48 100644 (file)
@@ -36,6 +36,7 @@ import org.sonar.scanner.protocol.output.ScannerReport;
 import org.sonar.server.computation.task.projectanalysis.analysis.Project;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.fail;
 import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder;
@@ -54,6 +55,7 @@ public class ComponentTreeBuilderTest {
     + ComponentKeys.createEffectiveKey(module.getKey(), component != null ? component.getPath() : null);
   private static final Function<String, String> UUID_SUPPLIER = (componentKey) -> componentKey + "_uuid";
   private static final EnumSet<ScannerReport.Component.ComponentType> REPORT_TYPES = EnumSet.of(PROJECT, MODULE, DIRECTORY, FILE);
+  private static final String NO_SCM_BASE_PATH = "";
 
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
@@ -81,7 +83,7 @@ public class ComponentTreeBuilderTest {
   }
 
   @Test
-  public void by_default_project_is_loaded_from_report() {
+  public void by_default_project_fields_are_loaded_from_report() {
     String nameInReport = "the name";
     String descriptionInReport = "the desc";
     Component root = call(newBuilder()
@@ -153,6 +155,114 @@ public class ComponentTreeBuilderTest {
     assertThat(root.getDescription()).isNull();
   }
 
+  @Test
+  public void project_scmPath_is_empty_if_scmBasePath_is_empty() {
+    Component root = call(newBuilder()
+      .setType(PROJECT)
+      .build(), NO_SCM_BASE_PATH);
+
+    assertThat(root.getReportAttributes().getScmPath()).isEmpty();
+  }
+
+  @Test
+  public void any_component_with_projectRelativePath_has_this_value_as_scmPath_if_scmBasePath_is_empty() {
+    String[] projectRelativePaths = {
+      randomAlphabetic(4),
+      randomAlphabetic(5),
+      randomAlphabetic(6),
+      randomAlphabetic(7)
+    };
+    ScannerReport.Component project = newBuilder()
+      .setType(PROJECT)
+      .setKey(projectInDb.getKey())
+      .setRef(1)
+      .addChildRef(2)
+      .setProjectRelativePath(projectRelativePaths[0])
+      .build();
+    scannerComponentProvider.add(newBuilder()
+      .setRef(2)
+      .setType(MODULE)
+      .setKey("M")
+      .setProjectRelativePath(projectRelativePaths[1])
+      .addChildRef(3));
+    scannerComponentProvider.add(newBuilder()
+      .setRef(3)
+      .setType(DIRECTORY)
+      .setPath("src/js")
+      .setProjectRelativePath(projectRelativePaths[2])
+      .addChildRef(4));
+    scannerComponentProvider.add(newBuilder()
+      .setRef(4)
+      .setType(FILE)
+      .setPath("src/js/Foo.js")
+      .setProjectRelativePath(projectRelativePaths[3])
+      .setLines(1));
+
+    Component root = call(project, NO_SCM_BASE_PATH);
+
+    assertThat(root.getReportAttributes().getScmPath())
+      .contains(projectRelativePaths[0]);
+    Component module = root.getChildren().iterator().next();
+    assertThat(module.getReportAttributes().getScmPath())
+      .contains(projectRelativePaths[1]);
+    Component directory = module.getChildren().iterator().next();
+    assertThat(directory.getReportAttributes().getScmPath())
+      .contains(projectRelativePaths[2]);
+    Component file = directory.getChildren().iterator().next();
+    assertThat(file.getReportAttributes().getScmPath())
+      .contains(projectRelativePaths[3]);
+  }
+
+  @Test
+  public void any_component_with_projectRelativePath_has_this_value_appended_to_scmBasePath_and_a_slash_as_scmPath_if_scmBasePath_is_not_empty() {
+    String[] projectRelativePaths = {
+      randomAlphabetic(4),
+      randomAlphabetic(5),
+      randomAlphabetic(6),
+      randomAlphabetic(7)
+    };
+    ScannerReport.Component project = newBuilder()
+      .setType(PROJECT)
+      .setKey(projectInDb.getKey())
+      .setRef(1)
+      .addChildRef(2)
+      .setProjectRelativePath(projectRelativePaths[0])
+      .build();
+    scannerComponentProvider.add(newBuilder()
+      .setRef(2)
+      .setType(MODULE)
+      .setKey("M")
+      .setProjectRelativePath(projectRelativePaths[1])
+      .addChildRef(3));
+    scannerComponentProvider.add(newBuilder()
+      .setRef(3)
+      .setType(DIRECTORY)
+      .setPath("src/js")
+      .setProjectRelativePath(projectRelativePaths[2])
+      .addChildRef(4));
+    scannerComponentProvider.add(newBuilder()
+      .setRef(4)
+      .setType(FILE)
+      .setPath("src/js/Foo.js")
+      .setProjectRelativePath(projectRelativePaths[3])
+      .setLines(1));
+    String scmBasePath = randomAlphabetic(10);
+
+    Component root = call(project, scmBasePath);
+
+    assertThat(root.getReportAttributes().getScmPath())
+      .contains(scmBasePath + "/" + projectRelativePaths[0]);
+    Component module = root.getChildren().iterator().next();
+    assertThat(module.getReportAttributes().getScmPath())
+      .contains(scmBasePath + "/" + projectRelativePaths[1]);
+    Component directory = module.getChildren().iterator().next();
+    assertThat(directory.getReportAttributes().getScmPath())
+      .contains(scmBasePath + "/" + projectRelativePaths[2]);
+    Component file = directory.getChildren().iterator().next();
+    assertThat(file.getReportAttributes().getScmPath())
+      .contains(scmBasePath + "/" + projectRelativePaths[3]);
+  }
+
   @Test
   public void keys_of_module_directory_and_file_are_generated() {
     ScannerReport.Component project = newBuilder()
@@ -732,11 +842,19 @@ public class ComponentTreeBuilderTest {
   }
 
   private Component call(ScannerReport.Component project) {
-    return newUnderTest(null).buildProject(project);
+    return call(project, NO_SCM_BASE_PATH);
+  }
+
+  private Component call(ScannerReport.Component project, String scmBasePath) {
+    return newUnderTest(null).buildProject(project, scmBasePath);
   }
 
   private Component call(ScannerReport.Component project, @Nullable SnapshotDto baseAnalysis) {
-    return newUnderTest(baseAnalysis).buildProject(project);
+    return call(project, baseAnalysis, NO_SCM_BASE_PATH);
+  }
+
+  private Component call(ScannerReport.Component project, @Nullable SnapshotDto baseAnalysis, String scmBasePath) {
+    return newUnderTest(baseAnalysis).buildProject(project, scmBasePath);
   }
 
   private ComponentTreeBuilder newUnderTest(@Nullable SnapshotDto baseAnalysis) {