Browse Source

SONAR-11631 replace Component.version by Metadata.projectVersion

in scanner report
tags/7.7
Sébastien Lesaint 5 years ago
parent
commit
47ebff25c3
23 changed files with 296 additions and 245 deletions
  1. 12
    11
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentTreeBuilder.java
  2. 3
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java
  3. 26
    27
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ComponentTreeBuilderTest.java
  4. 19
    4
      sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectDefinition.java
  5. 0
    13
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbstractProjectOrModule.java
  6. 1
    1
      sonar-plugin-api/src/test/java/org/sonar/api/batch/bootstrap/ProjectBuilderTest.java
  7. 2
    2
      sonar-plugin-api/src/test/java/org/sonar/api/batch/bootstrap/ProjectDefinitionTest.java
  8. 2
    5
      sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputProjectTest.java
  9. 23
    9
      sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectInfo.java
  10. 5
    5
      sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java
  11. 7
    7
      sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java
  12. 6
    6
      sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/IssueTransition.java
  13. 0
    5
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java
  14. 12
    9
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
  15. 1
    1
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputProjectProvider.java
  16. 0
    5
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java
  17. 2
    2
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
  18. 31
    18
      sonar-scanner-engine/src/test/java/org/sonar/scanner/ProjectInfoTest.java
  19. 6
    6
      sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/DefaultFilterableIssueTest.java
  20. 11
    14
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java
  21. 35
    4
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
  22. 88
    88
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java
  23. 4
    2
      sonar-scanner-protocol/src/main/protobuf/scanner_report.proto

+ 12
- 11
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/component/ComponentTreeBuilder.java View File

@@ -70,6 +70,8 @@ public class ComponentTreeBuilder {
private final Branch branch;
@Nullable
private final SnapshotDto baseAnalysis;
@Nullable
private final String projectVersion;
private final IssueRelocationToRoot issueRelocationToRoot;

private ScannerReport.Component rootComponent;
@@ -81,7 +83,9 @@ public class ComponentTreeBuilder {
Function<String, String> uuidSupplier,
Function<Integer, ScannerReport.Component> scannerComponentSupplier,
Project project,
Branch branch, @Nullable SnapshotDto baseAnalysis, IssueRelocationToRoot issueRelocationToRoot) {
Branch branch, @Nullable SnapshotDto baseAnalysis,
@Nullable String projectVersion,
IssueRelocationToRoot issueRelocationToRoot) {

this.keyGenerator = keyGenerator;
this.publicKeyGenerator = publicKeyGenerator;
@@ -90,6 +94,7 @@ public class ComponentTreeBuilder {
this.project = project;
this.branch = branch;
this.baseAnalysis = baseAnalysis;
this.projectVersion = projectVersion;
this.issueRelocationToRoot = issueRelocationToRoot;
}

@@ -193,7 +198,7 @@ public class ComponentTreeBuilder {
.setDbKey(projectKey)
.setKey(projectPublicKey)
.setStatus(convertStatus(rootComponent.getStatus()))
.setProjectAttributes(new ProjectAttributes(createProjectVersion(rootComponent)))
.setProjectAttributes(new ProjectAttributes(createProjectVersion()))
.setReportAttributes(createAttributesBuilder(rootComponent.getRef(), rootComponent.getProjectRelativePath(), scmBasePath).build())
.addChildren(children);
setNameAndDescription(rootComponent, builder);
@@ -334,16 +339,12 @@ public class ComponentTreeBuilder {
return project.getName();
}

private static String nameOfOthers(ScannerReport.Component reportComponent, String defaultName) {
String name = trimToNull(reportComponent.getName());
return name == null ? defaultName : name;
}

private String createProjectVersion(ScannerReport.Component component) {
String version = trimToNull(component.getVersion());
if (version != null) {
return version;
private String createProjectVersion() {
String cleanedProjectVersion = trimToNull(this.projectVersion);
if (cleanedProjectVersion != null) {
return cleanedProjectVersion;
}
// FIXME SONAR-11631 code below applies to the analysisVersion, not the project version, fix it
if (baseAnalysis != null) {
return firstNonNull(baseAnalysis.getVersion(), DEFAULT_PROJECT_VERSION);
}

+ 3
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/BuildComponentTreeStep.java View File

@@ -90,7 +90,9 @@ public class BuildComponentTreeStep implements ComputationStep {
reportReader::readComponent,
analysisMetadataHolder.getProject(),
analysisMetadataHolder.getBranch(),
baseAnalysis, issueRelocationToRoot);
baseAnalysis,
metadata.getProjectVersion(),
issueRelocationToRoot);
String relativePathFromScmRoot = metadata.getRelativePathFromScmRoot();

Component reportTreeRoot = builder.buildProject(reportProject, relativePathFromScmRoot);

+ 26
- 27
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/component/ComponentTreeBuilderTest.java View File

@@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.junit.Rule;
@@ -65,6 +66,8 @@ public class ComponentTreeBuilderTest {
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 = "";
// both no project as "" or null should be supported
private static final String NO_PROJECT_VERSION = new Random().nextBoolean() ? "" : null;

private IssueRelocationToRoot issueRelocationToRoot = mock(IssueRelocationToRoot.class);
@Rule
@@ -95,7 +98,7 @@ public class ComponentTreeBuilderTest {
.setProjectRelativePath("src")
.setLines(1));
try {
call(project);
call(project, NO_SCM_BASE_PATH, null);
fail("Should have thrown a IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Unsupported component type '" + type + "'");
@@ -130,8 +133,7 @@ public class ComponentTreeBuilderTest {
.setRef(42)
.setName(nameInReport)
.setDescription(descriptionInReport)
.setVersion("6.5")
.build());
.build(), NO_SCM_BASE_PATH, "6.5");

assertThat(root.getUuid()).isEqualTo("generated_K1_uuid");
assertThat(root.getDbKey()).isEqualTo("generated_K1");
@@ -149,7 +151,7 @@ public class ComponentTreeBuilderTest {
public void project_name_is_loaded_from_db_if_absent_from_report() {
Component root = call(newBuilder()
.setType(PROJECT)
.build());
.build(), NO_SCM_BASE_PATH, NO_PROJECT_VERSION);

assertThat(root.getName()).isEqualTo(projectInDb.getName());
}
@@ -162,7 +164,7 @@ public class ComponentTreeBuilderTest {
.setName(reportName)
.build();

Component root = newUnderTest(null, true).buildProject(reportProject, NO_SCM_BASE_PATH);
Component root = newUnderTest(null, true, NO_PROJECT_VERSION).buildProject(reportProject, NO_SCM_BASE_PATH);

assertThat(root.getName()).isEqualTo(reportName);
}
@@ -175,7 +177,8 @@ public class ComponentTreeBuilderTest {
.setName(reportName)
.build();

Component root = newUnderTest(null, false).buildProject(reportProject, NO_SCM_BASE_PATH);
Component root = newUnderTest(null, false, null)
.buildProject(reportProject, NO_SCM_BASE_PATH);

assertThat(root.getName()).isEqualTo(projectInDb.getName());
}
@@ -185,7 +188,7 @@ public class ComponentTreeBuilderTest {
SnapshotDto baseAnalysis = new SnapshotDto().setVersion("6.5");
Component root = call(newBuilder()
.setType(PROJECT)
.build(), baseAnalysis);
.build(), baseAnalysis, NO_SCM_BASE_PATH, NO_PROJECT_VERSION);

assertThat(root.getProjectAttributes().getVersion()).isEqualTo("6.5");
}
@@ -195,8 +198,7 @@ public class ComponentTreeBuilderTest {
SnapshotDto baseAnalysis = new SnapshotDto().setVersion("6.5");
Component root = call(newBuilder()
.setType(PROJECT)
.setVersion("")
.build(), baseAnalysis);
.build(), baseAnalysis, NO_SCM_BASE_PATH, NO_PROJECT_VERSION);

assertThat(root.getProjectAttributes().getVersion()).isEqualTo("6.5");
}
@@ -205,7 +207,7 @@ public class ComponentTreeBuilderTest {
public void project_version_is_hardcoded_if_absent_from_report_and_db() {
Component root = call(newBuilder()
.setType(PROJECT)
.build());
.build(), NO_SCM_BASE_PATH, NO_PROJECT_VERSION);

assertThat(root.getProjectAttributes().getVersion()).isEqualTo("not provided");
}
@@ -214,7 +216,7 @@ public class ComponentTreeBuilderTest {
public void project_description_is_loaded_from_db_if_absent_from_report() {
Component root = call(newBuilder()
.setType(PROJECT)
.build());
.build(), NO_SCM_BASE_PATH, NO_PROJECT_VERSION);

assertThat(root.getDescription()).isEqualTo(projectInDb.getDescription());
}
@@ -227,7 +229,7 @@ public class ComponentTreeBuilderTest {
.setDescription(reportDescription)
.build();

Component root = newUnderTest(null, true).buildProject(reportProject, NO_SCM_BASE_PATH);
Component root = newUnderTest(null, true, null).buildProject(reportProject, NO_SCM_BASE_PATH);

assertThat(root.getDescription()).isEqualTo(reportDescription);
}
@@ -240,7 +242,7 @@ public class ComponentTreeBuilderTest {
.setDescription(reportDescription)
.build();

Component root = newUnderTest(null, false).buildProject(reportProject, NO_SCM_BASE_PATH);
Component root = newUnderTest(null, false, null).buildProject(reportProject, NO_SCM_BASE_PATH);

assertThat(root.getDescription()).isEqualTo(projectInDb.getDescription());
}
@@ -249,7 +251,7 @@ public class ComponentTreeBuilderTest {
public void project_scmPath_is_empty_if_scmBasePath_is_empty() {
Component root = call(newBuilder()
.setType(PROJECT)
.build(), NO_SCM_BASE_PATH);
.build(), NO_SCM_BASE_PATH, NO_PROJECT_VERSION);

assertThat(root.getReportAttributes().getScmPath()).isEmpty();
}
@@ -269,7 +271,7 @@ public class ComponentTreeBuilderTest {
.setProjectRelativePath("src/js/Foo.js")
.setLines(1));

Component root = call(project, NO_SCM_BASE_PATH);
Component root = call(project, NO_SCM_BASE_PATH, NO_PROJECT_VERSION);

assertThat(root.getReportAttributes().getScmPath())
.contains("root");
@@ -286,7 +288,7 @@ public class ComponentTreeBuilderTest {
ScannerReport.Component project = createProject();
String scmBasePath = randomAlphabetic(10);

Component root = call(project, scmBasePath);
Component root = call(project, scmBasePath, NO_PROJECT_VERSION);
assertThat(root.getReportAttributes().getScmPath())
.contains(scmBasePath);
Component directory = root.getChildren().iterator().next();
@@ -901,25 +903,22 @@ public class ComponentTreeBuilderTest {
}

private Component call(ScannerReport.Component project) {
return call(project, NO_SCM_BASE_PATH);
return call(project, NO_SCM_BASE_PATH, NO_PROJECT_VERSION);
}

private Component call(ScannerReport.Component project, String scmBasePath) {
return newUnderTest(null, true).buildProject(project, scmBasePath);
private Component call(ScannerReport.Component project, String scmBasePath, @Nullable String projectVersion) {
return call(project, null, scmBasePath, projectVersion);
}

private Component call(ScannerReport.Component project, @Nullable SnapshotDto baseAnalysis) {
return call(project, baseAnalysis, NO_SCM_BASE_PATH);
private Component call(ScannerReport.Component project, @Nullable SnapshotDto baseAnalysis, String scmBasePath, @Nullable String projectVersion) {
return newUnderTest(baseAnalysis, true, projectVersion).buildProject(project, scmBasePath);
}

private Component call(ScannerReport.Component project, @Nullable SnapshotDto baseAnalysis, String scmBasePath) {
return newUnderTest(baseAnalysis, true).buildProject(project, scmBasePath);
}

private ComponentTreeBuilder newUnderTest(@Nullable SnapshotDto baseAnalysis, boolean mainBranch) {
private ComponentTreeBuilder newUnderTest(@Nullable SnapshotDto baseAnalysis, boolean mainBranch, @Nullable String projectVersion) {
Branch branch = mock(Branch.class);
when(branch.isMain()).thenReturn(mainBranch);
return new ComponentTreeBuilder(KEY_GENERATOR, PUBLIC_KEY_GENERATOR, UUID_SUPPLIER, scannerComponentProvider, projectInDb, branch, baseAnalysis,
return new ComponentTreeBuilder(KEY_GENERATOR, PUBLIC_KEY_GENERATOR, UUID_SUPPLIER, scannerComponentProvider,
projectInDb, branch, baseAnalysis, projectVersion,
issueRelocationToRoot);
}


+ 19
- 4
sonar-plugin-api/src/main/java/org/sonar/api/batch/bootstrap/ProjectDefinition.java View File

@@ -48,8 +48,6 @@ public class ProjectDefinition {

public static final String TESTS_PROPERTY = "sonar.tests";

public static final String BUILD_DIR_PROPERTY = "sonar.buildDir";

private static final char SEPARATOR = ',';

private File baseDir;
@@ -149,7 +147,7 @@ public class ProjectDefinition {
return this;
}

public ProjectDefinition setVersion(String s) {
public ProjectDefinition setProjectVersion(String s) {
properties.put(CoreProperties.PROJECT_VERSION_PROPERTY, StringUtils.defaultString(s));
return this;
}
@@ -191,12 +189,29 @@ public class ProjectDefinition {
return null;
}

/**
* @deprecated since 7.7, use {@link #getOriginalProjectVersion()} instead
*/
@Deprecated
@CheckForNull
public String getOriginalVersion() {
return properties.get(CoreProperties.PROJECT_VERSION_PROPERTY);
return getOriginalProjectVersion();
}

/**
* @deprecated since 7.7, use {@link #getProjectVersion()} instead
*/
@Deprecated
public String getVersion() {
return getProjectVersion();
}

@CheckForNull
public String getOriginalProjectVersion() {
return properties.get(CoreProperties.PROJECT_VERSION_PROPERTY);
}

public String getProjectVersion() {
String version = properties.get(CoreProperties.PROJECT_VERSION_PROPERTY);
if (StringUtils.isBlank(version)) {
version = "not provided";

+ 0
- 13
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/AbstractProjectOrModule.java View File

@@ -43,9 +43,7 @@ public abstract class AbstractProjectOrModule extends DefaultInputComponent {
private final Path baseDir;
private final Path workDir;
private final String name;
private final String version;
private final String originalName;
private final String originalVersion;
private final String description;
private final String keyWithBranch;
private final String branch;
@@ -61,8 +59,6 @@ public abstract class AbstractProjectOrModule extends DefaultInputComponent {
this.workDir = initWorkingDir(definition);
this.name = definition.getName();
this.originalName = definition.getOriginalName();
this.version = definition.getVersion();
this.originalVersion = definition.getOriginalVersion();
this.description = definition.getDescription();
this.keyWithBranch = definition.getKeyWithBranch();
this.branch = definition.getBranch();
@@ -145,15 +141,6 @@ public abstract class AbstractProjectOrModule extends DefaultInputComponent {
return properties;
}

@CheckForNull
public String getOriginalVersion() {
return originalVersion;
}

public String getVersion() {
return version;
}

@CheckForNull
public String getOriginalName() {
return originalName;

+ 1
- 1
sonar-plugin-api/src/test/java/org/sonar/api/batch/bootstrap/ProjectBuilderTest.java View File

@@ -66,7 +66,7 @@ public class ProjectBuilderTest {
subProject.setBaseDir(baseDir);
subProject.setWorkDir(new File(baseDir, "target/.sonar"));
subProject.setKey("groupId:parentProjectId");
subProject.setVersion(root.getOriginalVersion());
subProject.setProjectVersion(root.getOriginalVersion());
subProject.setName("Sub Project");
subProject.setSources("src");
root.addSubProject(subProject);

+ 2
- 2
sonar-plugin-api/src/test/java/org/sonar/api/batch/bootstrap/ProjectDefinitionTest.java View File

@@ -37,14 +37,14 @@ public class ProjectDefinitionTest {
@Test
public void shouldSetVersion() {
ProjectDefinition def = ProjectDefinition.create();
def.setVersion("2.0-SNAPSHOT");
def.setProjectVersion("2.0-SNAPSHOT");
assertThat(def.getVersion()).isEqualTo("2.0-SNAPSHOT");
}

@Test
public void shouldSupportNoVersion() {
ProjectDefinition def = ProjectDefinition.create();
def.setVersion(null);
def.setProjectVersion(null);
assertThat(def.getVersion()).isEqualTo("not provided");
assertThat(def.getOriginalVersion()).isEqualTo("");
}

+ 2
- 5
sonar-plugin-api/src/test/java/org/sonar/api/batch/fs/internal/DefaultInputProjectTest.java View File

@@ -42,7 +42,6 @@ public class DefaultInputProjectTest {
def.setName("projectName");
File baseDir = temp.newFolder();
def.setBaseDir(baseDir);
def.setVersion("version");
def.setDescription("desc");
File workDir = temp.newFolder();
def.setWorkDir(workDir);
@@ -57,13 +56,11 @@ public class DefaultInputProjectTest {
assertThat(project.getBranch()).isNull();
assertThat(project.getBaseDir()).isEqualTo(baseDir.toPath());
assertThat(project.getKeyWithBranch()).isEqualTo("projectKey");
assertThat(project.getVersion()).isEqualTo("version");
assertThat(project.getOriginalVersion()).isEqualTo("version");
assertThat(project.getDescription()).isEqualTo("desc");
assertThat(project.getWorkDir()).isEqualTo(workDir.toPath());
assertThat(project.getEncoding()).isEqualTo(Charset.defaultCharset());

assertThat(project.properties()).hasSize(6);
assertThat(project.properties()).hasSize(5);

assertThat(project.isFile()).isFalse();
}
@@ -75,7 +72,7 @@ public class DefaultInputProjectTest {
def.setName("projectName");
File baseDir = temp.newFolder();
def.setBaseDir(baseDir);
def.setVersion("version");
def.setProjectVersion("version");
def.setDescription("desc");
File workDir = temp.newFolder();
def.setWorkDir(workDir);

sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectAnalysisInfo.java → sonar-scanner-engine/src/main/java/org/sonar/scanner/ProjectInfo.java View File

@@ -22,24 +22,28 @@ package org.sonar.scanner;
import java.time.Clock;
import java.util.Date;
import java.util.Optional;
import javax.annotation.CheckForNull;
import org.picocontainer.Startable;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.MessageException;

import static java.lang.String.format;

/**
* @since 6.3
*
*
* Immutable after {@link #start()}
*/
public class ProjectAnalysisInfo implements Startable {
public class ProjectInfo implements Startable {
private final Clock clock;
private Configuration settings;

private Date analysisDate;
private String analysisVersion;
private String projectVersion;

public ProjectAnalysisInfo(Configuration settings, Clock clock) {
public ProjectInfo(Configuration settings, Clock clock) {
this.settings = settings;
this.clock = clock;
}
@@ -48,8 +52,9 @@ public class ProjectAnalysisInfo implements Startable {
return analysisDate;
}

public String analysisVersion() {
return analysisVersion;
@CheckForNull
public String projectVersion() {
return projectVersion;
}

private Date loadAnalysisDate() {
@@ -71,14 +76,23 @@ public class ProjectAnalysisInfo implements Startable {
}
}

private String loadAnalysisVersion() {
return settings.get(CoreProperties.PROJECT_VERSION_PROPERTY).orElse(null);
@CheckForNull
private String loadProjectVersion() {
return settings.get(CoreProperties.PROJECT_VERSION_PROPERTY)
.filter(version -> {
if (version.length() > 100) {
throw MessageException.of(format("\"%s\" is not a valid project version. " +
"The maximum length for version numbers is 100 characters.", version));
}
return true;
})
.orElse(null);
}

@Override
public void start() {
this.analysisDate = loadAnalysisDate();
this.analysisVersion = loadAnalysisVersion();
this.projectVersion = loadProjectVersion();
}

@Override

+ 5
- 5
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/DefaultFilterableIssue.java View File

@@ -30,19 +30,19 @@ import org.sonar.api.batch.fs.internal.DefaultTextPointer;
import org.sonar.api.batch.fs.internal.DefaultTextRange;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;

@ThreadSafe
public class DefaultFilterableIssue implements FilterableIssue {
private final Issue rawIssue;
private final InputComponent component;
private final ProjectAnalysisInfo projectAnalysisInfo;
private final ProjectInfo projectInfo;
private DefaultInputProject project;

public DefaultFilterableIssue(DefaultInputProject project, ProjectAnalysisInfo projectAnalysisInfo, Issue rawIssue, InputComponent component) {
public DefaultFilterableIssue(DefaultInputProject project, ProjectInfo projectInfo, Issue rawIssue, InputComponent component) {
this.project = project;
this.projectAnalysisInfo = projectAnalysisInfo;
this.projectInfo = projectInfo;
this.rawIssue = rawIssue;
this.component = component;
}
@@ -91,7 +91,7 @@ public class DefaultFilterableIssue implements FilterableIssue {

@Override
public Date creationDate() {
return projectAnalysisInfo.analysisDate();
return projectInfo.analysisDate();
}

@Override

+ 7
- 7
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueFilters.java View File

@@ -24,7 +24,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.scan.issue.filter.FilterableIssue;
import org.sonar.api.scan.issue.filter.IssueFilter;
import org.sonar.api.scan.issue.filter.IssueFilterChain;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.protocol.output.ScannerReport;

/**
@@ -34,20 +34,20 @@ import org.sonar.scanner.protocol.output.ScannerReport;
public class IssueFilters {
private final IssueFilterChain filterChain;
private final DefaultInputProject project;
private final ProjectAnalysisInfo projectAnalysisInfo;
private final ProjectInfo projectInfo;

public IssueFilters(DefaultInputProject project, ProjectAnalysisInfo projectAnalysisInfo, IssueFilter[] exclusionFilters) {
public IssueFilters(DefaultInputProject project, ProjectInfo projectInfo, IssueFilter[] exclusionFilters) {
this.project = project;
this.filterChain = new DefaultIssueFilterChain(exclusionFilters);
this.projectAnalysisInfo = projectAnalysisInfo;
this.projectInfo = projectInfo;
}

public IssueFilters(DefaultInputProject project, ProjectAnalysisInfo projectAnalysisInfo) {
this(project, projectAnalysisInfo, new IssueFilter[0]);
public IssueFilters(DefaultInputProject project, ProjectInfo projectInfo) {
this(project, projectInfo, new IssueFilter[0]);
}

public boolean accept(InputComponent component, ScannerReport.Issue rawIssue) {
FilterableIssue fIssue = new DefaultFilterableIssue(project, projectAnalysisInfo, rawIssue, component);
FilterableIssue fIssue = new DefaultFilterableIssue(project, projectInfo, rawIssue, component);
return filterChain.accept(fIssue);
}


+ 6
- 6
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/IssueTransition.java View File

@@ -28,7 +28,7 @@ import javax.annotation.Nullable;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputComponent;
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.issue.IssueCache;
import org.sonar.scanner.issue.IssueTransformer;
import org.sonar.scanner.protocol.output.ScannerReport;
@@ -45,17 +45,17 @@ public class IssueTransition {
@Nullable
private final LocalIssueTracking localIssueTracking;

public IssueTransition(InputComponentStore inputComponentCache, ProjectAnalysisInfo projectAnalysisInfo, IssueCache issueCache, ReportPublisher reportPublisher,
@Nullable LocalIssueTracking localIssueTracking) {
public IssueTransition(InputComponentStore inputComponentCache, ProjectInfo projectInfo, IssueCache issueCache, ReportPublisher reportPublisher,
@Nullable LocalIssueTracking localIssueTracking) {
this.inputComponentStore = inputComponentCache;
this.issueCache = issueCache;
this.reportPublisher = reportPublisher;
this.localIssueTracking = localIssueTracking;
this.analysisDate = projectAnalysisInfo.analysisDate();
this.analysisDate = projectInfo.analysisDate();
}

public IssueTransition(InputComponentStore inputComponentCache, ProjectAnalysisInfo projectAnalysisInfo, IssueCache issueCache, ReportPublisher reportPublisher) {
this(inputComponentCache, projectAnalysisInfo, issueCache, reportPublisher, null);
public IssueTransition(InputComponentStore inputComponentCache, ProjectInfo projectInfo, IssueCache issueCache, ReportPublisher reportPublisher) {
this(inputComponentCache, projectInfo, issueCache, reportPublisher, null);
}

public void execute() {

+ 0
- 5
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ComponentsPublisher.java View File

@@ -96,11 +96,6 @@ public class ComponentsPublisher implements ReportPublisherStep {
projectBuilder.setDescription(description);
}

String version = project.getOriginalVersion();
if (version != null) {
projectBuilder.setVersion(version);
}

writeLinks(project, projectBuilder);
return projectBuilder;
}

+ 12
- 9
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java View File

@@ -23,7 +23,6 @@ import java.io.File;
import java.nio.file.Path;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
@@ -32,7 +31,7 @@ import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.bootstrap.ScannerPlugin;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
import org.sonar.scanner.cpd.CpdSettings;
@@ -45,13 +44,16 @@ import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scm.ScmConfiguration;

import static java.util.Optional.ofNullable;
import static org.apache.commons.lang.StringUtils.trimToNull;

public class MetadataPublisher implements ReportPublisherStep {

private static final Logger LOG = Loggers.get(MetadataPublisher.class);

private final ScanProperties properties;
private final QualityProfiles qProfiles;
private final ProjectAnalysisInfo projectAnalysisInfo;
private final ProjectInfo projectInfo;
private final InputModuleHierarchy moduleHierarchy;
private final CpdSettings cpdSettings;
private final ScannerPluginRepository pluginRepository;
@@ -60,10 +62,10 @@ public class MetadataPublisher implements ReportPublisherStep {
@Nullable
private final ScmConfiguration scmConfiguration;

public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties,
public MetadataPublisher(ProjectInfo projectInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties,
QualityProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration,
@Nullable ScmConfiguration scmConfiguration) {
this.projectAnalysisInfo = projectAnalysisInfo;
this.projectInfo = projectInfo;
this.moduleHierarchy = moduleHierarchy;
this.properties = properties;
this.qProfiles = qProfiles;
@@ -73,20 +75,21 @@ public class MetadataPublisher implements ReportPublisherStep {
this.scmConfiguration = scmConfiguration;
}

public MetadataPublisher(ProjectAnalysisInfo projectAnalysisInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties,
public MetadataPublisher(ProjectInfo projectInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties,
QualityProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration) {
this(projectAnalysisInfo, moduleHierarchy, properties, qProfiles, cpdSettings, pluginRepository, branchConfiguration, null);
this(projectInfo, moduleHierarchy, properties, qProfiles, cpdSettings, pluginRepository, branchConfiguration, null);
}

@Override
public void publish(ScannerReportWriter writer) {
AbstractProjectOrModule rootProject = moduleHierarchy.root();
ScannerReport.Metadata.Builder builder = ScannerReport.Metadata.newBuilder()
.setAnalysisDate(projectAnalysisInfo.analysisDate().getTime())
.setAnalysisDate(projectInfo.analysisDate().getTime())
// Here we want key without branch
.setProjectKey(rootProject.key())
.setCrossProjectDuplicationActivated(cpdSettings.isCrossProjectDuplicationEnabled())
.setRootComponentRef(rootProject.scannerId());
ofNullable(trimToNull(projectInfo.projectVersion())).ifPresent(builder::setProjectVersion);

properties.organizationKey().ifPresent(builder::setOrganizationKey);

@@ -94,7 +97,7 @@ public class MetadataPublisher implements ReportPublisherStep {
addBranchInformation(builder);
}

Optional.ofNullable(rootProject.getBranch()).ifPresent(builder::setDeprecatedBranch);
ofNullable(rootProject.getBranch()).ifPresent(builder::setDeprecatedBranch);

if (scmConfiguration != null) {
addScmInformation(builder);

+ 1
- 1
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/InputProjectProvider.java View File

@@ -35,7 +35,7 @@ public class InputProjectProvider extends ProviderAdapter {
private DefaultInputProject project = null;

public DefaultInputProject provide(ProjectBuildersExecutor projectBuildersExecutor, ProjectReactorValidator validator,
ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) {
ProjectReactor projectReactor, ScannerComponentIdGenerator scannerComponentIdGenerator) {
if (project == null) {
// 1 Apply project builders
projectBuildersExecutor.execute(projectReactor);

+ 0
- 5
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectReactorValidator.java View File

@@ -120,11 +120,6 @@ public class ProjectReactorValidator {
validationMessages.add(format("\"%s\" is not a valid project or module key. "
+ "Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", moduleDef.getKey()));
}
String originalVersion = moduleDef.getOriginalVersion();
if (originalVersion != null && originalVersion.length() > 100) {
validationMessages.add(format("\"%s\" is not a valid version name for module \"%s\". " +
"The maximum length for version numbers is 100 characters.", originalVersion, moduleDef.getKey()));
}
}

private static void validateBranch(List<String> validationMessages, @Nullable String branch) {

+ 2
- 2
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java View File

@@ -37,7 +37,7 @@ import org.sonar.core.extension.CoreExtensionsInstaller;
import org.sonar.core.metric.ScannerMetrics;
import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.DefaultFileLinesContextFactory;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.analysis.AnalysisTempFolderProvider;
import org.sonar.scanner.analysis.DefaultAnalysisMode;
import org.sonar.scanner.bootstrap.ExtensionInstaller;
@@ -167,7 +167,7 @@ public class ProjectScanContainer extends ComponentContainer {
ResourceTypes.class,
ProjectReactorValidator.class,
MetricProvider.class,
ProjectAnalysisInfo.class,
ProjectInfo.class,
Storages.class,
new RulesProvider(),
new BranchConfigurationProvider(),

sonar-scanner-engine/src/test/java/org/sonar/scanner/ProjectAnalysisInfoTest.java → sonar-scanner-engine/src/test/java/org/sonar/scanner/ProjectInfoTest.java View File

@@ -30,51 +30,64 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.MessageException;

import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class ProjectAnalysisInfoTest {
public class ProjectInfoTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

private MapSettings settings = new MapSettings();
private Clock clock = mock(Clock.class);
private ProjectInfo underTest = new ProjectInfo(settings.asConfig(), clock);

@Test
public void testSimpleDateTime() {
MapSettings settings = new MapSettings();
OffsetDateTime date = OffsetDateTime.of(2017, 1, 1, 12, 13, 14, 0, ZoneOffset.ofHours(2));
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01T12:13:14+0200");
settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version");
Clock clock = mock(Clock.class);
ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings.asConfig(), clock);
info.start();
OffsetDateTime date = OffsetDateTime.of(2017, 1, 1, 12, 13, 14, 0, ZoneOffset.ofHours(2));

assertThat(info.analysisDate()).isEqualTo(Date.from(date.toInstant()));
assertThat(info.analysisVersion()).isEqualTo("version");
underTest.start();

assertThat(underTest.analysisDate()).isEqualTo(Date.from(date.toInstant()));
assertThat(underTest.projectVersion()).isEqualTo("version");
}

@Test
public void testSimpleDate() {
MapSettings settings = new MapSettings();
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01");
Clock clock = mock(Clock.class);
ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings.asConfig(), clock);
info.start();
LocalDate date = LocalDate.of(2017, 1, 1);
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01");

underTest.start();

assertThat(info.analysisDate()).isEqualTo(Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
assertThat(underTest.analysisDate())
.isEqualTo(Date.from(date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
}

@Test
public void emptyDate() {
MapSettings settings = new MapSettings();
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "");
settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, "version");
Clock clock = mock(Clock.class);
ProjectAnalysisInfo info = new ProjectAnalysisInfo(settings.asConfig(), clock);

thrown.expect(RuntimeException.class);

info.start();
underTest.start();
}

@Test
public void fail_with_too_long_version() {
String version = randomAlphabetic(101);
settings.appendProperty(CoreProperties.PROJECT_DATE_PROPERTY, "2017-01-01");
settings.appendProperty(CoreProperties.PROJECT_VERSION_PROPERTY, version);

thrown.expect(MessageException.class);
thrown.expectMessage("\"" + version +"\" is not a valid project version. " +
"The maximum length for version numbers is 100 characters.");

underTest.start();
}
}

+ 6
- 6
sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/DefaultFilterableIssueTest.java View File

@@ -24,7 +24,7 @@ import org.junit.Before;
import org.junit.Test;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.protocol.Constants.Severity;
import org.sonar.scanner.protocol.output.ScannerReport.Issue;
import org.sonar.scanner.protocol.output.ScannerReport.TextRange;
@@ -36,14 +36,14 @@ import static org.mockito.Mockito.when;
public class DefaultFilterableIssueTest {
private DefaultFilterableIssue issue;
private DefaultInputProject mockedProject;
private ProjectAnalysisInfo projectAnalysisInfo;
private ProjectInfo projectInfo;
private InputComponent component;
private Issue rawIssue;

@Before
public void setUp() {
mockedProject = mock(DefaultInputProject.class);
projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
projectInfo = mock(ProjectInfo.class);
component = mock(InputComponent.class);
when(component.key()).thenReturn("foo");
}
@@ -70,9 +70,9 @@ public class DefaultFilterableIssueTest {
@Test
public void testRoundTrip() {
rawIssue = createIssue();
issue = new DefaultFilterableIssue(mockedProject, projectAnalysisInfo, rawIssue, component);
issue = new DefaultFilterableIssue(mockedProject, projectInfo, rawIssue, component);

when(projectAnalysisInfo.analysisDate()).thenReturn(new Date(10_000));
when(projectInfo.analysisDate()).thenReturn(new Date(10_000));
when(mockedProject.key()).thenReturn("projectKey");

assertThat(issue.componentKey()).isEqualTo(component.key());
@@ -90,7 +90,7 @@ public class DefaultFilterableIssueTest {
@Test
public void nullValues() {
rawIssue = createIssueWithoutFields();
issue = new DefaultFilterableIssue(mockedProject, projectAnalysisInfo, rawIssue, component);
issue = new DefaultFilterableIssue(mockedProject, projectInfo, rawIssue, component);

assertThat(issue.line()).isNull();
assertThat(issue.gap()).isNull();

+ 11
- 14
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java View File

@@ -35,7 +35,7 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.utils.DateUtils;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Component;
@@ -73,8 +73,8 @@ public class ComponentsPublisherTest {

@Test
public void add_components_to_report() throws Exception {
ProjectAnalysisInfo projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
when(projectAnalysisInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));
ProjectInfo projectInfo = mock(ProjectInfo.class);
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));

ProjectDefinition rootDef = ProjectDefinition.create()
.setKey("foo")
@@ -128,7 +128,6 @@ public class ComponentsPublisherTest {
Component rootProtobuf = reader.readComponent(1);
assertThat(rootProtobuf.getKey()).isEqualTo("foo");
assertThat(rootProtobuf.getDescription()).isEqualTo("Root description");
assertThat(rootProtobuf.getVersion()).isEqualTo("1.0");
assertThat(rootProtobuf.getLinkCount()).isEqualTo(0);

assertThat(reader.readComponent(4).getStatus()).isEqualTo(FileStatus.SAME);
@@ -138,8 +137,8 @@ public class ComponentsPublisherTest {

@Test
public void should_set_modified_name_with_branch() throws IOException {
ProjectAnalysisInfo projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
when(projectAnalysisInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));
ProjectInfo projectInfo = mock(ProjectInfo.class);
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));

ProjectDefinition rootDef = ProjectDefinition.create()
.setKey("foo")
@@ -162,8 +161,8 @@ public class ComponentsPublisherTest {
@Test
public void publish_unchanged_components_even_in_short_branches() throws IOException {
when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
ProjectAnalysisInfo projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
when(projectAnalysisInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));
ProjectInfo projectInfo = mock(ProjectInfo.class);
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));

Path baseDir = temp.newFolder().toPath();
ProjectDefinition rootDef = ProjectDefinition.create()
@@ -202,8 +201,8 @@ public class ComponentsPublisherTest {

@Test
public void publish_project_without_version_and_name() throws IOException {
ProjectAnalysisInfo projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
when(projectAnalysisInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));
ProjectInfo projectInfo = mock(ProjectInfo.class);
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));

ProjectDefinition rootDef = ProjectDefinition.create()
.setKey("foo")
@@ -223,14 +222,13 @@ public class ComponentsPublisherTest {
assertThat(rootProtobuf.getKey()).isEqualTo("foo");
assertThat(rootProtobuf.getName()).isEqualTo("");
assertThat(rootProtobuf.getDescription()).isEqualTo("Root description");
assertThat(rootProtobuf.getVersion()).isEqualTo("");
assertThat(rootProtobuf.getLinkCount()).isEqualTo(0);
}

@Test
public void publish_project_with_links_and_branch() throws Exception {
ProjectAnalysisInfo projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
when(projectAnalysisInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));
ProjectInfo projectInfo = mock(ProjectInfo.class);
when(projectInfo.analysisDate()).thenReturn(DateUtils.parseDate("2012-12-12"));

ProjectDefinition rootDef = ProjectDefinition.create()
.setKey("foo")
@@ -250,7 +248,6 @@ public class ComponentsPublisherTest {

ScannerReportReader reader = new ScannerReportReader(outputDir);
Component rootProtobuf = reader.readComponent(1);
assertThat(rootProtobuf.getVersion()).isEqualTo("1.0");
assertThat(rootProtobuf.getLinkCount()).isEqualTo(2);
assertThat(rootProtobuf.getLink(0).getType()).isEqualTo(ComponentLinkType.HOME);
assertThat(rootProtobuf.getLink(0).getHref()).isEqualTo("http://home");

+ 35
- 4
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java View File

@@ -20,6 +20,9 @@
package org.sonar.scanner.report;

import com.google.common.collect.ImmutableMap;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@@ -28,17 +31,19 @@ import java.nio.file.Paths;
import java.util.Collections;
import java.util.Date;
import java.util.Optional;
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.scm.ScmProvider;
import org.sonar.scanner.ProjectAnalysisInfo;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.bootstrap.ScannerPlugin;
import org.sonar.scanner.bootstrap.ScannerPluginRepository;
import org.sonar.scanner.cpd.CpdSettings;
@@ -60,6 +65,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(DataProviderRunner.class)
public class MetadataPublisherTest {

@Rule
@@ -69,7 +75,7 @@ public class MetadataPublisherTest {
private MetadataPublisher underTest;
private ScanProperties properties = mock(ScanProperties.class);
private QualityProfiles qProfiles = mock(QualityProfiles.class);
private ProjectAnalysisInfo projectAnalysisInfo = mock(ProjectAnalysisInfo.class);
private ProjectInfo projectInfo = mock(ProjectInfo.class);
private CpdSettings cpdSettings = mock(CpdSettings.class);
private InputModuleHierarchy inputModuleHierarchy;
private ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
@@ -79,7 +85,7 @@ public class MetadataPublisherTest {

@Before
public void prepare() throws IOException {
when(projectAnalysisInfo.analysisDate()).thenReturn(new Date(1234567L));
when(projectInfo.analysisDate()).thenReturn(new Date(1234567L));
when(scmProvider.relativePathFromScmRoot(any(Path.class))).thenReturn(Paths.get("dummy/path"));
when(scmProvider.revisionId(any(Path.class))).thenReturn("dummy-sha1");

@@ -107,7 +113,7 @@ public class MetadataPublisherTest {
branches = mock(BranchConfiguration.class);
scmConfiguration = mock(ScmConfiguration.class);
when(scmConfiguration.provider()).thenReturn(scmProvider);
underTest = new MetadataPublisher(projectAnalysisInfo, inputModuleHierarchy, properties, qProfiles, cpdSettings,
underTest = new MetadataPublisher(projectInfo, inputModuleHierarchy, properties, qProfiles, cpdSettings,
pluginRepository, branches, scmConfiguration);
}

@@ -180,6 +186,31 @@ public class MetadataPublisherTest {
assertThat(metadata.getOrganizationKey()).isEqualTo("SonarSource");
}

@Test
@UseDataProvider("projectVersions")
public void write_project_version(@Nullable String projectVersion, String expected) throws Exception {
when(projectInfo.projectVersion()).thenReturn(projectVersion);
when(properties.organizationKey()).thenReturn(Optional.of("SonarSource"));

File outputDir = temp.newFolder();
ScannerReportWriter writer = new ScannerReportWriter(outputDir);

underTest.publish(writer);

ScannerReportReader reader = new ScannerReportReader(outputDir);
ScannerReport.Metadata metadata = reader.readMetadata();
assertThat(metadata.getProjectVersion()).isEqualTo(expected);
}

@DataProvider
public static Object[][] projectVersions() {
return new Object[][] {
{null, ""},
{"", ""},
{"5.6.3", "5.6.3"}
};
}

@Test
public void write_long_lived_branch_info() throws Exception {
String branchName = "long-lived";

+ 88
- 88
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ProjectReactorValidatorTest.java View File

@@ -19,96 +19,83 @@
*/
package org.sonar.scanner.scan;

import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.Optional;
import java.util.function.Consumer;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.utils.MessageException;
import org.sonar.core.config.ScannerProperties;
import org.sonar.scanner.ProjectInfo;
import org.sonar.scanner.bootstrap.GlobalConfiguration;

import static org.apache.commons.lang.StringUtils.repeat;
import static org.apache.commons.lang.RandomStringUtils.randomAscii;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@RunWith(DataProviderRunner.class)
public class ProjectReactorValidatorTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

private AnalysisMode mode;
private ProjectReactorValidator validator;
private GlobalConfiguration settings;
private AnalysisMode mode = mock(AnalysisMode.class);
private GlobalConfiguration settings = mock(GlobalConfiguration.class);
private ProjectInfo projectInfo = mock(ProjectInfo.class);
private ProjectReactorValidator underTest = new ProjectReactorValidator(mode, settings);

@Before
public void prepare() {
mode = mock(AnalysisMode.class);
settings = mock(GlobalConfiguration.class);
when(settings.get(anyString())).thenReturn(Optional.empty());
validator = new ProjectReactorValidator(mode, settings);
}

@Test
public void not_fail_with_valid_key() {
validator.validate(createProjectReactor("foo"));
validator.validate(createProjectReactor("123foo"));
validator.validate(createProjectReactor("foo123"));
validator.validate(createProjectReactor("1Z3"));
validator.validate(createProjectReactor("a123"));
validator.validate(createProjectReactor("123a"));
validator.validate(createProjectReactor("1:2"));
validator.validate(createProjectReactor("3-3"));
validator.validate(createProjectReactor("-:"));
@UseDataProvider("validKeys")
public void not_fail_with_valid_key(String validKey) {
underTest.validate(createProjectReactor(validKey));
}

@DataProvider
public static Object[][] validKeys() {
return new Object[][] {
{"foo"},
{"123foo"},
{"foo123"},
{"1Z3"},
{"a123"},
{"123a"},
{"1:2"},
{"3-3"},
{"-:"},
{"Foobar2"},
{"foo.bar"},
{"foo-bar"},
{"foo:bar"},
{"foo_bar"}
};
}

@Test
public void allow_slash_issues_mode() {
when(mode.isIssues()).thenReturn(true);
validator.validate(createProjectReactor("project/key"));
underTest.validate(createProjectReactor("project/key"));

when(mode.isIssues()).thenReturn(false);
thrown.expect(MessageException.class);
thrown.expectMessage("is not a valid project or module key");
validator.validate(createProjectReactor("project/key"));
}

@Test
public void not_fail_with_alphanumeric_key() {
ProjectReactor reactor = createProjectReactor("Foobar2");
validator.validate(reactor);
}

@Test
public void should_not_fail_with_dot_key() {
ProjectReactor reactor = createProjectReactor("foo.bar");
validator.validate(reactor);
}

@Test
public void not_fail_with_dash_key() {
ProjectReactor reactor = createProjectReactor("foo-bar");
validator.validate(reactor);
}

@Test
public void not_fail_with_colon_key() {
ProjectReactor reactor = createProjectReactor("foo:bar");
validator.validate(reactor);
}

@Test
public void not_fail_with_underscore_key() {
ProjectReactor reactor = createProjectReactor("foo_bar");
validator.validate(reactor);
underTest.validate(createProjectReactor("project/key"));
}

@Test
@@ -117,7 +104,7 @@ public class ProjectReactorValidatorTest {

thrown.expect(MessageException.class);
thrown.expectMessage("\"foo$bar\" is not a valid project or module key");
validator.validate(reactor);
underTest.validate(reactor);
}

@Test
@@ -126,33 +113,46 @@ public class ProjectReactorValidatorTest {

thrown.expect(MessageException.class);
thrown.expectMessage("\"foo\\bar\" is not a valid project or module key");
validator.validate(reactor);
underTest.validate(reactor);
}

@Test
public void not_fail_with_valid_branch() {
validator.validate(createProjectReactor("foo", "branch"));
validator.validate(createProjectReactor("foo", "Branch2"));
validator.validate(createProjectReactor("foo", "bra.nch"));
validator.validate(createProjectReactor("foo", "bra-nch"));
validator.validate(createProjectReactor("foo", "1"));
validator.validate(createProjectReactor("foo", "bra_nch"));
@UseDataProvider("validBranches")
public void not_fail_with_valid_branch(String validBranch) {
ProjectReactor reactor = createProjectReactor("foo", validBranch);

underTest.validate(reactor);
}

@Test
public void fail_with_invalid_branch() {
ProjectReactor reactor = createProjectReactor("foo", "bran#ch");
thrown.expect(MessageException.class);
thrown.expectMessage("\"bran#ch\" is not a valid branch name");
validator.validate(reactor);
@DataProvider
public static Object[][] validBranches() {
return new Object[][] {
{"branch"},
{"Branch2"},
{"bra.nch"},
{"bra-nch"},
{"1"},
{"bra_nch"}
};
}

@Test
public void fail_with_colon_in_branch() {
ProjectReactor reactor = createProjectReactor("foo", "bran:ch");
@UseDataProvider("invalidBranches")
public void fail_with_invalid_branch(String invalidBranch) {
ProjectReactor reactor = createProjectReactor("foo", invalidBranch);

thrown.expect(MessageException.class);
thrown.expectMessage("\"bran:ch\" is not a valid branch name");
validator.validate(reactor);
thrown.expectMessage("\"" + invalidBranch + "\" is not a valid branch name");

underTest.validate(reactor);
}

@DataProvider
public static Object[][] invalidBranches() {
return new Object[][] {
{"bran#ch"},
{"bran:ch"}
};
}

@Test
@@ -161,7 +161,8 @@ public class ProjectReactorValidatorTest {

thrown.expect(MessageException.class);
thrown.expectMessage("\"12345\" is not a valid project or module key");
validator.validate(reactor);

underTest.validate(reactor);
}

@Test
@@ -174,7 +175,7 @@ public class ProjectReactorValidatorTest {
thrown.expect(MessageException.class);
thrown.expectMessage("the branch plugin is required but not installed");

validator.validate(reactor);
underTest.validate(reactor);
}

@Test
@@ -187,7 +188,7 @@ public class ProjectReactorValidatorTest {
thrown.expect(MessageException.class);
thrown.expectMessage("the branch plugin is required but not installed");

validator.validate(reactor);
underTest.validate(reactor);
}

@Test
@@ -200,7 +201,7 @@ public class ProjectReactorValidatorTest {
thrown.expect(MessageException.class);
thrown.expectMessage("the branch plugin is required but not installed");

validator.validate(reactor);
underTest.validate(reactor);
}

@Test
@@ -213,7 +214,7 @@ public class ProjectReactorValidatorTest {
thrown.expect(MessageException.class);
thrown.expectMessage("the branch plugin is required but not installed");

validator.validate(reactor);
underTest.validate(reactor);
}

@Test
@@ -226,25 +227,24 @@ public class ProjectReactorValidatorTest {
thrown.expect(MessageException.class);
thrown.expectMessage("the branch plugin is required but not installed");

validator.validate(reactor);
}

@Test
public void not_fail_with_valid_version() {
validator.validate(createProjectReactor("foo", def -> def.setVersion("1.0")));
validator.validate(createProjectReactor("foo", def -> def.setVersion("2017-10-16")));
validator.validate(createProjectReactor("foo", def -> def.setVersion(repeat("a", 100))));
underTest.validate(reactor);
}

@Test
public void fail_with_too_long_version() {
ProjectReactor reactor = createProjectReactor("foo", def -> def.setVersion(repeat("a", 101)));
@UseDataProvider("validVersions")
public void not_fail_with_valid_version(String validVersion) {
when(projectInfo.projectVersion()).thenReturn(validVersion);

thrown.expect(MessageException.class);
thrown.expectMessage("\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" is not a valid version name for module \"foo\". " +
"The maximum length for version numbers is 100 characters.");
underTest.validate(createProjectReactor("foo"));
}

validator.validate(reactor);
@DataProvider
public static Object[][] validVersions() {
return new Object[][] {
{"1.0"},
{"2017-10-16"},
{randomAscii(100)}
};
}

private ProjectReactor createProjectReactor(String projectKey, String branch) {

+ 4
- 2
sonar-scanner-protocol/src/main/protobuf/scanner_report.proto View File

@@ -49,6 +49,8 @@ message Metadata {
string pull_request_key = 14;
map<string, string> modules_project_relative_path_by_key = 15;

string projectVersion = 16;

message QProfile {
string key = 1;
string name = 2;
@@ -108,7 +110,7 @@ message Component {
string language = 6;
repeated int32 child_ref = 7 [packed = true];
repeated ComponentLink link = 8;
// Only available on PROJECT and MODULE types
// FIXME SONAR-11631 delete this property after deployment on SC of metadata.projectVersion
string version = 9;
// Only available on PROJECT and MODULE types
// TODO rename this property -> moduleKey ?
@@ -121,7 +123,7 @@ message Component {

// Path relative to project base directory
string project_relative_path = 14;
enum ComponentType {
UNSET = 0;
PROJECT = 1;

Loading…
Cancel
Save