From: Julien Lancelot Date: Wed, 30 Aug 2017 09:50:05 +0000 (+0200) Subject: SONAR-9616 Add public key in Component of CE X-Git-Tag: 6.6-RC1~380^2~32 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=da92a11875a68ee82fb157f71b530ff12cb82b6f;p=sonarqube.git SONAR-9616 Add public key in Component of CE --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolder.java index 624d16b58b9..de4cc6ee2c8 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/analysis/MutableAnalysisMetadataHolder.java @@ -58,7 +58,7 @@ public interface MutableAnalysisMetadataHolder extends AnalysisMetadataHolder { /** * @throws IllegalStateException if branch has already been set */ - MutableAnalysisMetadataHolder setBranch(@Nullable Branch branch); + MutableAnalysisMetadataHolder setBranch(@Nullable Branch branch); /** * @throws IllegalStateException if project has already been set diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/Component.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/Component.java index a2be3b3a097..20b43ed1ae9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/Component.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/Component.java @@ -78,6 +78,14 @@ public interface Component { */ String getKey(); + /** + * Returns the key as it will be displayed in the ui. + * If legacy branch feature is used, the key will contain the branch name + * If new branch feature is used, the key will not contain the branch name + */ + // TODO to be renamed getKey() and rename existing getKey to getDbKey + String getPublicKey(); + /** * The component name. */ diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentImpl.java index e7686fa9d2f..100c92cdae9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentImpl.java @@ -38,6 +38,7 @@ public class ComponentImpl implements Component { private final Status status; private final String name; private final String key; + private final String publicKey; private final String uuid; @CheckForNull @@ -52,6 +53,7 @@ public class ComponentImpl implements Component { this.type = builder.type; this.status = builder.status; this.key = builder.key; + this.publicKey = builder.publicKey; this.name = builder.name; this.description = builder.description; this.uuid = builder.uuid; @@ -80,6 +82,11 @@ public class ComponentImpl implements Component { return key; } + @Override + public String getPublicKey() { + return publicKey; + } + @Override public String getName() { return this.name; @@ -139,6 +146,7 @@ public class ComponentImpl implements Component { private ReportAttributes reportAttributes; private String uuid; private String key; + private String publicKey; private String name; private String description; private FileAttributes fileAttributes; @@ -173,6 +181,11 @@ public class ComponentImpl implements Component { return this; } + public Builder setPublicKey(String publicKey) { + this.publicKey = requireNonNull(publicKey); + return this; + } + public Builder setName(String name) { this.name = requireNonNull(name, NAME_CANNOT_BE_NULL); return this; diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilder.java deleted file mode 100644 index 75a964a0e40..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/ComponentRootBuilder.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.computation.task.projectanalysis.component; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.MoreObjects; -import com.google.common.base.Optional; -import com.google.common.base.Supplier; -import java.util.function.Function; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.scanner.protocol.output.ScannerReport; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.collect.Iterables.toArray; -import static java.lang.String.format; -import static org.apache.commons.lang.StringUtils.trimToNull; -import static org.sonar.core.component.ComponentKeys.createEffectiveKey; -import static org.sonar.core.component.ComponentKeys.createKey; -import static org.sonar.core.util.stream.MoreCollectors.toList; - -public class ComponentRootBuilder { - private static final String DEFAULT_PROJECT_VERSION = "not provided"; - - /** - * Will supply the UUID for any component in the tree, given it's key. - *

- * The String argument of the {@link Function#apply(Object)} method is the component's key. - *

- */ - private final Function uuidSupplier; - /** - * Will supply the {@link ScannerReport.Component} of all the components in the component tree as we crawl it from the - * root. - *

- * The Integer argument of the {@link Function#apply(Object)} method is the component's ref. - *

- */ - private final Function scannerComponentSupplier; - /** - * Will supply the ComponentDto of the project (if it exists) if we need it to get the name of the project - * - * @see #nameOfProject(ScannerReport.Component, String, Supplier) - */ - private final Supplier> projectDtoSupplier; - /** - * Will supply the SnapshotDto of the base analysis of the project (if it exists) if we need it to get the version - * of the project. - *

- * The String argument of the {@link Function#apply(Object)} method is the project's UUID. - *

- * - * @see #createProjectVersion(ScannerReport.Component, String, Function) - */ - private final Function> analysisSupplier; - @CheckForNull - private final String branch; - - public ComponentRootBuilder(@Nullable String branch, - Function uuidSupplier, - Function scannerComponentSupplier, - Supplier> projectDtoSupplier, - Function> analysisSupplier) { - this.uuidSupplier = uuidSupplier; - this.scannerComponentSupplier = scannerComponentSupplier; - this.projectDtoSupplier = projectDtoSupplier; - this.branch = branch; - this.analysisSupplier = analysisSupplier; - } - - public Component build(ScannerReport.Component reportProject, String projectKey) { - return buildComponent(reportProject, projectKey); - } - - private ComponentImpl buildComponent(ScannerReport.Component reportComponent, String latestModuleKey) { - switch (reportComponent.getType()) { - case PROJECT: - return buildProjectComponent(reportComponent, latestModuleKey); - case MODULE: - String moduleKey = createKey(reportComponent.getKey(), branch); - return buildOtherComponent(reportComponent, moduleKey, moduleKey); - case DIRECTORY: - case FILE: - return buildOtherComponent(reportComponent, createEffectiveKey(latestModuleKey, reportComponent.getPath()), latestModuleKey); - default: - throw new IllegalArgumentException(format("Unsupported component type '%s'", reportComponent.getType())); - } - } - - private ComponentImpl buildProjectComponent(ScannerReport.Component reportComponent, String latestModuleKey) { - ComponentImpl.Builder builder = createCommonBuilder(reportComponent, latestModuleKey, latestModuleKey); - return builder - .setName(nameOfProject(reportComponent, latestModuleKey, projectDtoSupplier)) - .setReportAttributes(createProjectReportAttributes(reportComponent, builder.getUuid(), analysisSupplier)) - .build(); - } - - private ComponentImpl buildOtherComponent(ScannerReport.Component reportComponent, String componentKey, String latestModuleKey) { - return createCommonBuilder(reportComponent, componentKey, latestModuleKey) - .setName(nameOfOthers(reportComponent, componentKey)) - .setReportAttributes(createOtherReportAttributes(reportComponent)) - .build(); - } - - private ComponentImpl.Builder createCommonBuilder(ScannerReport.Component reportComponent, String componentKey, String latestModuleKey) { - return ComponentImpl.builder(convertType(reportComponent.getType())) - .setUuid(uuidSupplier.apply(componentKey)) - .setKey(componentKey) - .setStatus(convertStatus(reportComponent.getStatus())) - .setDescription(trimToNull(reportComponent.getDescription())) - .setFileAttributes(createFileAttributes(reportComponent)) - .addChildren(toArray(buildChildren(reportComponent, latestModuleKey), Component.class)); - } - - private Iterable buildChildren(ScannerReport.Component component, String latestModuleKey) { - return component.getChildRefList() - .stream() - .map(componentRef -> buildComponent(scannerComponentSupplier.apply(componentRef), latestModuleKey)) - .collect(toList(component.getChildRefList().size())); - } - - private static String nameOfProject(ScannerReport.Component project, String projectKey, Supplier> projectDtoSupplier) { - String name = trimToNull(project.getName()); - if (name == null) { - return projectDtoSupplier.get().transform(ComponentDto::name).or(projectKey); - } - return name; - } - - private static String nameOfOthers(ScannerReport.Component reportComponent, String componentKey) { - String name = trimToNull(reportComponent.getName()); - return name == null ? componentKey : name; - } - - @VisibleForTesting - static ReportAttributes createProjectReportAttributes(ScannerReport.Component component, - String projectUuid, Function> analysisSupplier) { - return createCommonBuilder(component) - .setVersion(createProjectVersion(component, projectUuid, analysisSupplier)) - .build(); - } - - private static String createProjectVersion(ScannerReport.Component component, - String projectUuid, Function> analysisSupplier) { - String version = trimToNull(component.getVersion()); - if (version != null) { - return version; - } - Optional snapshotDto = analysisSupplier.apply(projectUuid); - if (snapshotDto.isPresent()) { - return MoreObjects.firstNonNull(snapshotDto.get().getVersion(), DEFAULT_PROJECT_VERSION); - } - return DEFAULT_PROJECT_VERSION; - } - - @VisibleForTesting - static ReportAttributes createOtherReportAttributes(ScannerReport.Component component) { - return createCommonBuilder(component) - .setVersion(trimToNull(component.getVersion())) - .build(); - } - - private static ReportAttributes.Builder createCommonBuilder(ScannerReport.Component component) { - return ReportAttributes.newBuilder(component.getRef()) - .setPath(trimToNull(component.getPath())); - } - - @VisibleForTesting - @CheckForNull - static FileAttributes createFileAttributes(ScannerReport.Component component) { - if (component.getType() != ScannerReport.Component.ComponentType.FILE) { - return null; - } - - checkArgument(component.getLines() > 0, "File '%s' has no line", component.getPath()); - return new FileAttributes( - component.getIsTest(), - trimToNull(component.getLanguage()), - component.getLines()); - } - - static Component.Status convertStatus(ScannerReport.Component.FileStatus status) { - switch(status) { - case ADDED: - return Component.Status.ADDED; - case SAME: - return Component.Status.SAME; - case CHANGED: - return Component.Status.CHANGED; - case UNAVAILABLE: - return Component.Status.UNAVAILABLE; - case UNRECOGNIZED: - default: - throw new IllegalArgumentException("Unsupported ComponentType value " + status); - } - } - - @VisibleForTesting - static Component.Type convertType(ScannerReport.Component.ComponentType type) { - switch (type) { - case PROJECT: - return Component.Type.PROJECT; - case MODULE: - return Component.Type.MODULE; - case DIRECTORY: - return Component.Type.DIRECTORY; - case FILE: - return Component.Type.FILE; - default: - throw new IllegalArgumentException("Unsupported ComponentType value " + type); - } - } -} 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 3b8439a9533..ec277ceac4f 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 @@ -37,6 +37,7 @@ public class ComponentTreeBuilder { private static final String DEFAULT_PROJECT_VERSION = "not provided"; private final ComponentKeyGenerator keyGenerator; + private final ComponentKeyGenerator publicKeyGenerator; /** * Will supply the UUID for any component in the tree, given it's key. *

@@ -61,12 +62,14 @@ public class ComponentTreeBuilder { public ComponentTreeBuilder( ComponentKeyGenerator keyGenerator, + ComponentKeyGenerator publicKeyGenerator, Function uuidSupplier, Function scannerComponentSupplier, Project project, @Nullable SnapshotDto baseAnalysis) { this.keyGenerator = keyGenerator; + this.publicKeyGenerator = publicKeyGenerator; this.uuidSupplier = uuidSupplier; this.scannerComponentSupplier = scannerComponentSupplier; this.project = project; @@ -93,6 +96,7 @@ public class ComponentTreeBuilder { return ComponentImpl.builder(Component.Type.PROJECT) .setUuid(uuid) .setKey(projectKey) + .setPublicKey(publicKeyGenerator.generateKey(component, null)) .setName(nameOfProject(component)) .setStatus(convertStatus(component.getStatus())) .setDescription(trimToNull(component.getDescription())) @@ -107,6 +111,7 @@ public class ComponentTreeBuilder { return ComponentImpl.builder(Component.Type.MODULE) .setUuid(uuidSupplier.apply(moduleKey)) .setKey(moduleKey) + .setPublicKey(publicKeyGenerator.generateKey(component, null)) .setName(nameOfOthers(component, moduleKey)) .setStatus(convertStatus(component.getStatus())) .setDescription(trimToNull(component.getDescription())) @@ -120,6 +125,7 @@ public class ComponentTreeBuilder { return ComponentImpl.builder(convertDirOrFileType(component.getType())) .setUuid(uuidSupplier.apply(key)) .setKey(key) + .setPublicKey(publicKeyGenerator.generateKey(closestModule, component)) .setName(nameOfOthers(component, key)) .setStatus(convertStatus(component.getStatus())) .setDescription(trimToNull(component.getDescription())) 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 11a5e840fae..6a029818e4f 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 @@ -23,25 +23,23 @@ import java.util.Optional; import java.util.stream.Stream; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import org.sonar.core.component.ComponentKeys; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.SnapshotDto; import org.sonar.db.component.SnapshotQuery; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.server.computation.task.projectanalysis.analysis.Analysis; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReader; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.ComponentKeyGenerator; import org.sonar.server.computation.task.projectanalysis.component.ComponentTreeBuilder; import org.sonar.server.computation.task.projectanalysis.component.ComponentUuidFactory; +import org.sonar.server.computation.task.projectanalysis.component.DefaultBranchImpl; import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolder; import org.sonar.server.computation.task.step.ComputationStep; -import static org.apache.commons.lang.StringUtils.isEmpty; -import static org.apache.commons.lang.StringUtils.trimToNull; - /** * Populates the {@link MutableTreeRootHolder} and {@link MutableAnalysisMetadataHolder} from the {@link BatchReportReader} */ @@ -70,6 +68,7 @@ public class BuildComponentTreeStep implements ComputationStep { try (DbSession dbSession = dbClient.openSession(false)) { ScannerReport.Component reportProject = reportReader.readComponent(analysisMetadataHolder.getRootComponentRef()); ComponentKeyGenerator keyGenerator = loadKeyGenerator(); + ComponentKeyGenerator publicKeyGenerator = loadPublicKeyGenerator(); // root key of branch, not necessarily of project String rootKey = keyGenerator.generateKey(reportProject, null); @@ -80,7 +79,7 @@ public class BuildComponentTreeStep implements ComputationStep { String rootUuid = componentUuidFactory.getOrCreateForKey(rootKey); SnapshotDto baseAnalysis = loadBaseAnalysis(dbSession, rootUuid); - ComponentTreeBuilder builder = new ComponentTreeBuilder(keyGenerator, + ComponentTreeBuilder builder = new ComponentTreeBuilder(keyGenerator, publicKeyGenerator, componentUuidFactory::getOrCreateForKey, reportReader::readComponent, analysisMetadataHolder.getProject(), @@ -93,7 +92,7 @@ public class BuildComponentTreeStep implements ComputationStep { } private ComponentKeyGenerator loadKeyGenerator() { - return Stream.of(analysisMetadataHolder.getBranch(), Optional.of(new DefaultKeyGenerator())) + return Stream.of(analysisMetadataHolder.getBranch(), Optional.of(new DefaultBranchImpl())) // TODO pull request generator will be added here .filter(Optional::isPresent) .flatMap(x -> x.map(Stream::of).orElseGet(Stream::empty)) @@ -101,6 +100,17 @@ public class BuildComponentTreeStep implements ComputationStep { .get(); } + private ComponentKeyGenerator loadPublicKeyGenerator() { + Optional branch = analysisMetadataHolder.getBranch(); + if (!branch.isPresent()) { + // Used for pull request + return new DefaultBranchImpl(); + } + return branch.filter(Branch::isLegacyFeature) + .map(b -> new DefaultBranchImpl(b.getName().orElse(null))) + .orElseGet(DefaultBranchImpl::new); + } + @CheckForNull private SnapshotDto loadBaseAnalysis(DbSession dbSession, String rootUuid) { return dbClient.snapshotDao().selectAnalysisByQuery( @@ -122,14 +132,4 @@ public class BuildComponentTreeStep implements ComputationStep { return null; } - private static class DefaultKeyGenerator implements ComponentKeyGenerator { - @Override - public String generateKey(ScannerReport.Component module, @Nullable ScannerReport.Component fileOrDir) { - String moduleKey = module.getKey(); - if (fileOrDir == null || isEmpty(fileOrDir.getPath())) { - return moduleKey; - } - return ComponentKeys.createEffectiveKey(moduleKey, trimToNull(fileOrDir.getPath())); - } - } } 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 6697a44b266..ce41606865c 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 @@ -38,18 +38,20 @@ import org.sonar.server.computation.task.projectanalysis.analysis.Project; import static com.google.common.base.Preconditions.checkArgument; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; +import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder; import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.DIRECTORY; import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE; import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.MODULE; import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT; import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED; -import static org.sonar.scanner.protocol.output.ScannerReport.Component.newBuilder; import static org.sonar.server.computation.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER; public class ComponentTreeBuilderTest { private static final ComponentKeyGenerator KEY_GENERATOR = (module, component) -> "generated_" + ComponentKeys.createEffectiveKey(module.getKey(), component != null ? component.getPath() : null); + private static final ComponentKeyGenerator PUBLIC_KEY_GENERATOR = (module, component) -> "public_" + + 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); @@ -93,6 +95,7 @@ public class ComponentTreeBuilderTest { assertThat(root.getUuid()).isEqualTo("generated_K1_uuid"); assertThat(root.getKey()).isEqualTo("generated_K1"); + assertThat(root.getPublicKey()).isEqualTo("public_K1"); assertThat(root.getType()).isEqualTo(Component.Type.PROJECT); assertThat(root.getName()).isEqualTo(nameInReport); assertThat(root.getDescription()).isEqualTo(descriptionInReport); @@ -176,23 +179,27 @@ public class ComponentTreeBuilderTest { Component root = call(project); assertThat(root.getKey()).isEqualTo("generated_" + projectInDb.getKey()); + assertThat(root.getPublicKey()).isEqualTo("public_" + projectInDb.getKey()); assertThat(root.getChildren()).hasSize(1); Component module = root.getChildren().iterator().next(); assertThat(module.getKey()).isEqualTo("generated_M"); + assertThat(module.getPublicKey()).isEqualTo("public_M"); assertThat(module.getChildren()).hasSize(1); Component directory = module.getChildren().iterator().next(); assertThat(directory.getKey()).isEqualTo("generated_M:src/js"); + assertThat(directory.getPublicKey()).isEqualTo("public_M:src/js"); assertThat(directory.getChildren()).hasSize(1); Component file = directory.getChildren().iterator().next(); assertThat(file.getKey()).isEqualTo("generated_M:src/js/Foo.js"); + assertThat(file.getPublicKey()).isEqualTo("public_M:src/js/Foo.js"); assertThat(file.getChildren()).isEmpty(); } @Test - public void names_of_module_directory_and_file_are_keys_if_names_are_absent_from_report() { + public void names_of_module_directory_and_file_are_public_keys_if_names_are_absent_from_report() { ScannerReport.Component project = newBuilder() .setType(PROJECT) .setKey(projectInDb.getKey()) @@ -276,7 +283,7 @@ public class ComponentTreeBuilderTest { } @Test - public void name_of_module_directory_and_files_includes_name_of_closest_module() { + public void keys_of_module_directory_and_files_includes_name_of_closest_module() { ScannerReport.Component project = newBuilder() .setType(PROJECT) .setKey("project 1") @@ -301,20 +308,35 @@ public class ComponentTreeBuilderTest { Component root = call(project); Map componentsByRef = indexComponentByRef(root); assertThat(componentsByRef.get(11).getKey()).isEqualTo("generated_module 1"); + assertThat(componentsByRef.get(11).getPublicKey()).isEqualTo("public_module 1"); assertThat(componentsByRef.get(12).getKey()).isEqualTo("generated_module 2"); + assertThat(componentsByRef.get(12).getPublicKey()).isEqualTo("public_module 2"); assertThat(componentsByRef.get(13).getKey()).isEqualTo("generated_module 3"); + assertThat(componentsByRef.get(13).getPublicKey()).isEqualTo("public_module 3"); assertThat(componentsByRef.get(21).getKey()).startsWith("generated_project 1:"); + assertThat(componentsByRef.get(21).getPublicKey()).startsWith("public_project 1:"); assertThat(componentsByRef.get(22).getKey()).startsWith("generated_module 1:"); + assertThat(componentsByRef.get(22).getPublicKey()).startsWith("public_module 1:"); assertThat(componentsByRef.get(23).getKey()).startsWith("generated_module 2:"); + assertThat(componentsByRef.get(23).getPublicKey()).startsWith("public_module 2:"); assertThat(componentsByRef.get(24).getKey()).startsWith("generated_module 3:"); + assertThat(componentsByRef.get(24).getPublicKey()).startsWith("public_module 3:"); assertThat(componentsByRef.get(31).getKey()).startsWith("generated_project 1:"); + assertThat(componentsByRef.get(31).getPublicKey()).startsWith("public_project 1:"); assertThat(componentsByRef.get(32).getKey()).startsWith("generated_module 1:"); + assertThat(componentsByRef.get(32).getPublicKey()).startsWith("public_module 1:"); assertThat(componentsByRef.get(33).getKey()).startsWith("generated_module 2:"); + assertThat(componentsByRef.get(33).getPublicKey()).startsWith("public_module 2:"); assertThat(componentsByRef.get(34).getKey()).startsWith("generated_module 3:"); + assertThat(componentsByRef.get(34).getPublicKey()).startsWith("public_module 3:"); assertThat(componentsByRef.get(35).getKey()).startsWith("generated_project 1:"); + assertThat(componentsByRef.get(35).getPublicKey()).startsWith("public_project 1:"); assertThat(componentsByRef.get(36).getKey()).startsWith("generated_module 1:"); + assertThat(componentsByRef.get(36).getPublicKey()).startsWith("public_module 1:"); assertThat(componentsByRef.get(37).getKey()).startsWith("generated_module 2:"); + assertThat(componentsByRef.get(37).getPublicKey()).startsWith("public_module 2:"); assertThat(componentsByRef.get(38).getKey()).startsWith("generated_module 3:"); + assertThat(componentsByRef.get(38).getPublicKey()).startsWith("public_module 3:"); } @Test @@ -718,7 +740,7 @@ public class ComponentTreeBuilderTest { } private ComponentTreeBuilder newUnderTest(@Nullable SnapshotDto baseAnalysis) { - return new ComponentTreeBuilder(KEY_GENERATOR, UUID_SUPPLIER, scannerComponentProvider, projectInDb, baseAnalysis); + return new ComponentTreeBuilder(KEY_GENERATOR, PUBLIC_KEY_GENERATOR, UUID_SUPPLIER, scannerComponentProvider, projectInDb, baseAnalysis); } private static Map indexComponentByRef(Component root) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ReportComponent.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ReportComponent.java index f4f27679803..e3baec1c188 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ReportComponent.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ReportComponent.java @@ -22,13 +22,13 @@ package org.sonar.server.computation.task.projectanalysis.component; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static java.util.Arrays.asList; +import static java.util.Objects.requireNonNull; /** * Implementation of {@link Component} to unit test report components. @@ -45,6 +45,7 @@ public class ReportComponent implements Component { @CheckForNull private final String description; private final String key; + private final String publicKey; private final String uuid; private final ReportAttributes reportAttributes; private final FileAttributes fileAttributes; @@ -54,6 +55,7 @@ public class ReportComponent implements Component { this.type = builder.type; this.status = builder.status; this.key = builder.key; + this.publicKey = builder.publicKey; this.name = builder.name == null ? String.valueOf(builder.key) : builder.name; this.description = builder.description; this.uuid = builder.uuid; @@ -91,6 +93,14 @@ public class ReportComponent implements Component { return key; } + @Override + public String getPublicKey() { + if (publicKey == null) { + throw new UnsupportedOperationException(String.format("Component key of ref '%d' has not be fed yet", this.reportAttributes.getRef())); + } + return publicKey; + } + @Override public String getName() { return this.name; @@ -169,6 +179,7 @@ public class ReportComponent implements Component { private Status status; private String uuid; private String key; + private String publicKey; private String name; private String version; private String description; @@ -183,12 +194,12 @@ public class ReportComponent implements Component { } public Builder setStatus(Status s) { - this.status = Objects.requireNonNull(s); + this.status = requireNonNull(s); return this; } public Builder setUuid(String s) { - this.uuid = Objects.requireNonNull(s); + this.uuid = requireNonNull(s); return this; } @@ -198,7 +209,12 @@ public class ReportComponent implements Component { } public Builder setKey(String s) { - this.key = Objects.requireNonNull(s); + this.key = requireNonNull(s); + return this; + } + + public Builder setPublicKey(String publicKey) { + this.publicKey = requireNonNull(publicKey); return this; } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ViewsComponent.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ViewsComponent.java index b9fbf989025..5c249e3cad9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ViewsComponent.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/ViewsComponent.java @@ -152,6 +152,14 @@ public class ViewsComponent implements Component { return key; } + /** + * Views has no branch feature, the public key is the same as the key + */ + @Override + public String getPublicKey() { + return getKey(); + } + @Override public String getName() { checkState(this.name != null, "No name has been set"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java index 072d0ae3170..dc330355cd2 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/BuildComponentTreeStepTest.java @@ -24,6 +24,7 @@ import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import javax.annotation.Nullable; import org.junit.Rule; import org.junit.Test; @@ -37,10 +38,12 @@ import org.sonar.db.organization.OrganizationDto; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType; import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus; +import org.sonar.server.computation.task.projectanalysis.analysis.Branch; import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule; import org.sonar.server.computation.task.projectanalysis.analysis.Project; import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule; import org.sonar.server.computation.task.projectanalysis.component.Component; +import org.sonar.server.computation.task.projectanalysis.component.DefaultBranchImpl; import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolderRule; import static com.google.common.base.Predicates.in; @@ -48,6 +51,9 @@ import static com.google.common.base.Predicates.not; import static com.google.common.collect.FluentIterable.from; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.sonar.db.component.ComponentTesting.newDirectory; import static org.sonar.db.component.ComponentTesting.newFileDto; import static org.sonar.db.component.ComponentTesting.newModuleDto; @@ -83,21 +89,23 @@ public class BuildComponentTreeStepTest { @Rule public DbTester dbTester = DbTester.create(System2.INSTANCE); @Rule - public BatchReportReaderRule reportReader = new BatchReportReaderRule(); + public BatchReportReaderRule reportReader = new BatchReportReaderRule() + .setMetadata(ScannerReport.Metadata.newBuilder() + .setProjectKey(REPORT_PROJECT_KEY) + .setRootComponentRef(ROOT_REF) + .build()); @Rule public MutableTreeRootHolderRule treeRootHolder = new MutableTreeRootHolderRule(); @Rule - public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule() - .setRootComponentRef(ROOT_REF) - .setAnalysisDate(ANALYSIS_DATE) - .setBranch(null) - .setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY)); + public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule(); private DbClient dbClient = dbTester.getDbClient(); private BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); @Test(expected = NullPointerException.class) public void fails_if_root_component_does_not_exist_in_reportReader() { + setAnalysisMetadataHolder(); + underTest.execute(); } @@ -115,6 +123,7 @@ public class BuildComponentTreeStepTest { @Test @UseDataProvider("allComponentTypes") public void verify_ref_and_type(ComponentType componentType) { + setAnalysisMetadataHolder(); int componentRef = 1; reportReader.putComponent(component(componentRef, componentType)); @@ -129,6 +138,7 @@ public class BuildComponentTreeStepTest { @Test public void verify_tree_is_correctly_built() { + setAnalysisMetadataHolder(); reportReader.putComponent(component(ROOT_REF, PROJECT, MODULE_REF)); reportReader.putComponent(component(MODULE_REF, MODULE, DIR_REF_1, DIR_REF_2)); reportReader.putComponent(component(DIR_REF_1, DIRECTORY, FILE_1_REF, FILE_2_REF)); @@ -155,6 +165,7 @@ public class BuildComponentTreeStepTest { @Test public void compute_keys_and_uuids() { + setAnalysisMetadataHolder(); reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); @@ -170,6 +181,7 @@ public class BuildComponentTreeStepTest { @Test public void return_existing_uuids() { + setAnalysisMetadataHolder(); OrganizationDto organizationDto = dbTester.organizations().insert(); ComponentDto project = insertComponent(newPrivateProjectDto(organizationDto, "ABCD").setDbKey(REPORT_PROJECT_KEY)); ComponentDto module = insertComponent(newModuleDto("BCDE", project).setDbKey(REPORT_MODULE_KEY)); @@ -190,30 +202,99 @@ public class BuildComponentTreeStepTest { verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1, "DEFG"); } -// @Test -// public void use_branch_to_generate_keys() { -// MutableAnalysisMetadataHolder analysisMetadataHolder = new AnalysisMetadataHolderImpl() -// .setRootComponentRef(ROOT_REF) -// .setAnalysisDate(ANALYSIS_DATE) -// .setBranch("origin/master"); -// -// BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); -// -// reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); -// reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); -// reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); -// reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); -// -// underTest.execute(); -// -// verifyComponent(ROOT_REF, REPORT_PROJECT_KEY + ":origin/master"); -// verifyComponent(MODULE_REF, REPORT_MODULE_KEY + ":origin/master"); -// verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":origin/master:" + REPORT_DIR_KEY_1); -// verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":origin/master:" + REPORT_FILE_KEY_1); -// } + @Test + public void generate_keys_when_using_branch() { + Branch branch = mock(Branch.class); + when(branch.getName()).thenReturn(Optional.of("origin/feature")); + when(branch.isMain()).thenReturn(false); + when(branch.isLegacyFeature()).thenReturn(false); + when(branch.generateKey(any(ScannerReport.Component.class), any(ScannerReport.Component.class))).thenReturn("generated"); + analysisMetadataHolder.setRootComponentRef(ROOT_REF) + .setAnalysisDate(ANALYSIS_DATE) + .setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY)) + .setBranch(branch); + BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); + reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); + reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); + reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); + reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); + + underTest.execute(); + + verifyComponent(ROOT_REF, "generated", REPORT_PROJECT_KEY, null); + verifyComponent(MODULE_REF, "generated", REPORT_MODULE_KEY, null); + verifyComponent(DIR_REF_1, "generated", REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1, null); + verifyComponent(FILE_1_REF, "generated", REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1, null); + } + + @Test + public void generate_keys_when_using_main_branch() { + Branch branch = mock(Branch.class); + when(branch.getName()).thenReturn(Optional.of("origin/master")); + when(branch.isMain()).thenReturn(true); + when(branch.isLegacyFeature()).thenReturn(false); + when(branch.generateKey(any(ScannerReport.Component.class), any(ScannerReport.Component.class))).thenReturn("generated"); + analysisMetadataHolder.setRootComponentRef(ROOT_REF) + .setAnalysisDate(ANALYSIS_DATE) + .setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY)) + .setBranch(branch); + BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); + reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); + reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); + reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); + reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); + + underTest.execute(); + + verifyComponent(ROOT_REF, "generated", REPORT_PROJECT_KEY, null); + verifyComponent(MODULE_REF, "generated", REPORT_MODULE_KEY, null); + verifyComponent(DIR_REF_1, "generated", REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1, null); + verifyComponent(FILE_1_REF, "generated", REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1, null); + } + + @Test + public void generate_keys_when_using_legacy_branch() { + analysisMetadataHolder.setRootComponentRef(ROOT_REF) + .setAnalysisDate(ANALYSIS_DATE) + .setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY)) + .setBranch(new DefaultBranchImpl("origin/feature")); + BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); + reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); + reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); + reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); + reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); + + underTest.execute(); + + verifyComponent(ROOT_REF, REPORT_PROJECT_KEY + ":origin/feature", null); + verifyComponent(MODULE_REF, REPORT_MODULE_KEY + ":origin/feature", null); + verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":origin/feature:" + REPORT_DIR_KEY_1, null); + verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":origin/feature:" + REPORT_FILE_KEY_1, null); + } + + @Test + public void compute_keys_when_no_branch() { + analysisMetadataHolder.setRootComponentRef(ROOT_REF) + .setAnalysisDate(ANALYSIS_DATE) + .setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY)) + .setBranch(null); + BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder); + reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); + reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); + reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); + reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1)); + + underTest.execute(); + + verifyComponent(ROOT_REF, REPORT_PROJECT_KEY); + verifyComponent(MODULE_REF, REPORT_MODULE_KEY); + verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1); + verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1); + } @Test public void compute_keys_and_uuids_on_project_having_module_and_directory() { + setAnalysisMetadataHolder(); reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF, DIR_REF_2)); reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1)); reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF)); @@ -233,6 +314,7 @@ public class BuildComponentTreeStepTest { @Test public void compute_keys_and_uuids_on_multi_modules() { + setAnalysisMetadataHolder(); reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF)); reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, 100)); reportReader.putComponent(componentWithKey(100, MODULE, "SUB_MODULE_KEY", DIR_REF_1)); @@ -250,6 +332,7 @@ public class BuildComponentTreeStepTest { @Test public void return_existing_uuids_when_components_were_removed() { + setAnalysisMetadataHolder(); OrganizationDto organizationDto = dbTester.organizations().insert(); ComponentDto project = insertComponent(newPrivateProjectDto(organizationDto, "ABCD").setDbKey(REPORT_PROJECT_KEY)); ComponentDto removedModule = insertComponent(newModuleDto("BCDE", project).setDbKey(REPORT_MODULE_KEY).setEnabled(false)); @@ -273,6 +356,7 @@ public class BuildComponentTreeStepTest { @Test public void set_no_base_project_snapshot_when_no_snapshot() throws Exception { + setAnalysisMetadataHolder(); reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY)); underTest.execute(); @@ -281,6 +365,7 @@ public class BuildComponentTreeStepTest { @Test public void set_no_base_project_snapshot_when_no_last_snapshot() throws Exception { + setAnalysisMetadataHolder(); OrganizationDto organizationDto = dbTester.organizations().insert(); ComponentDto project = insertComponent(newPrivateProjectDto(organizationDto, "ABCD").setDbKey(REPORT_PROJECT_KEY)); insertSnapshot(newAnalysis(project).setLast(false)); @@ -293,6 +378,7 @@ public class BuildComponentTreeStepTest { @Test public void set_base_project_snapshot_when_last_snapshot_exist() throws Exception { + setAnalysisMetadataHolder(); OrganizationDto organizationDto = dbTester.organizations().insert(); ComponentDto project = insertComponent(newPrivateProjectDto(organizationDto, "ABCD").setDbKey(REPORT_PROJECT_KEY)); insertSnapshot(newAnalysis(project).setLast(true)); @@ -310,13 +396,18 @@ public class BuildComponentTreeStepTest { } private void verifyComponent(int ref, String key) { - verifyComponent(ref, key, null); + verifyComponent(ref, key, key, null); } private void verifyComponent(int ref, String key, @Nullable String uuid) { + verifyComponent(ref, key, key, uuid); + } + + private void verifyComponent(int ref, String key, String publicKey, @Nullable String uuid) { Map componentsByRef = indexAllComponentsInTreeByRef(treeRootHolder.getRoot()); Component component = componentsByRef.get(ref); assertThat(component.getKey()).isEqualTo(key); + assertThat(component.getPublicKey()).isEqualTo(publicKey); if (uuid != null) { assertThat(component.getUuid()).isEqualTo(uuid); } else { @@ -379,4 +470,11 @@ public class BuildComponentTreeStepTest { return snapshot; } + private void setAnalysisMetadataHolder() { + analysisMetadataHolder.setRootComponentRef(ROOT_REF) + .setAnalysisDate(ANALYSIS_DATE) + .setBranch(new DefaultBranchImpl(null)) + .setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY)); + } + }