From ec804c4ee14131a5cf4aa0113546a46737b86409 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Fri, 15 Dec 2017 15:01:22 +0100 Subject: [PATCH] SONAR-10126 add scmPath to ReportAttributes --- .../component/ComponentTreeBuilder.java | 42 ++++-- .../component/ReportAttributes.java | 22 ++++ .../step/BuildComponentTreeStep.java | 3 +- .../component/ComponentTreeBuilderTest.java | 124 +++++++++++++++++- 4 files changed, 173 insertions(+), 18 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java index 0581d636b86..219919562ba 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilder.java @@ -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 buildChildren(ScannerReport.Component component, ScannerReport.Component parentModule) { + private List 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 diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ReportAttributes.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ReportAttributes.java index 0c7e5db435c..f560d6852be 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ReportAttributes.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ReportAttributes.java @@ -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. + *

+ * 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 getScmPath() { + return Optional.ofNullable(scmPath); + } + @Override public String toString() { return "ReportAttributes{" + "ref=" + ref + ", version='" + version + '\'' + ", path='" + path + '\'' + + ", scmPath='" + scmPath + '\'' + '}'; } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java index fffb6cb5db0..4af8a4019e1 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStep.java @@ -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)); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java index 663125a229e..baddf91b3af 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ComponentTreeBuilderTest.java @@ -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 UUID_SUPPLIER = (componentKey) -> componentKey + "_uuid"; private static final EnumSet 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) { -- 2.39.5