Parcourir la source

SONAR-11508, SONAR-11484 Index files at project level

tags/7.6
Julien HENRY il y a 5 ans
Parent
révision
cc9d2163a0
34 fichiers modifiés avec 731 ajouts et 677 suppressions
  1. 2
    1
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFileFilter.java
  2. 0
    4
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java
  3. 7
    6
      sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileExclusions.java
  4. 3
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java
  5. 2
    24
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractModulePhaseExecutor.java
  6. 5
    7
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java
  7. 5
    7
      sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java
  8. 9
    11
      sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfileVerifier.java
  9. 0
    25
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java
  10. 32
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
  11. 171
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java
  12. 0
    132
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ExclusionFilters.java
  13. 91
    204
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
  14. 2
    5
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java
  15. 0
    71
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java
  16. 7
    10
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java
  17. 35
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleExclusionFilters.java
  18. 31
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFilters.java
  19. 168
    0
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java
  20. 1
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java
  21. 124
    32
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java
  22. 1
    3
      sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java
  23. 5
    5
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java
  24. 1
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java
  25. 1
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java
  26. 1
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java
  27. 12
    11
      sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java
  28. 1
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java
  29. 2
    2
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java
  30. 0
    91
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputFileBuilderTest.java
  31. 2
    5
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java
  32. 1
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java
  33. 8
    11
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java
  34. 1
    1
      sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java

+ 2
- 1
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputFileFilter.java Voir le fichier

@@ -20,12 +20,13 @@
package org.sonar.api.batch.fs;

import org.sonar.api.ExtensionPoint;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.scanner.ScannerSide;
import org.sonarsource.api.sonarlint.SonarLintSide;

/**
* Extension point to exclude some files from inspection
* @since 4.2
* @since 7.6 evaluated at project level
*/
@ScannerSide
@SonarLintSide

+ 0
- 4
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java Voir le fichier

@@ -26,11 +26,8 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
import org.sonar.api.batch.fs.internal.charhandler.FileHashComputer;
@@ -42,7 +39,6 @@ import org.sonar.api.batch.fs.internal.charhandler.LineOffsetCounter;
* Computes hash of files. Ends of Lines are ignored, so files with
* same content but different EOL encoding have the same hash.
*/
@ScannerSide
@Immutable
public class FileMetadata {
private static final char LINE_FEED = '\n';

+ 7
- 6
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileExclusions.java Voir le fichier

@@ -37,10 +37,11 @@ import org.sonar.api.config.Configuration;
@Deprecated
@ScannerSide
public class FileExclusions {
private final Configuration settings;

public FileExclusions(Configuration settings) {
this.settings = settings;
private final Configuration config;

public FileExclusions(Configuration config) {
this.config = config;
}

public String[] sourceInclusions() {
@@ -52,7 +53,7 @@ public class FileExclusions {
}

private String[] inclusions(String propertyKey) {
return Arrays.stream(settings.getStringArray(propertyKey))
return Arrays.stream(config.getStringArray(propertyKey))
.map(StringUtils::trim)
.filter(s -> !"**/*".equals(s))
.filter(s -> !"file:**/*".equals(s))
@@ -68,8 +69,8 @@ public class FileExclusions {
}

private String[] exclusions(String globalExclusionsProperty, String exclusionsProperty) {
String[] globalExclusions = settings.getStringArray(globalExclusionsProperty);
String[] exclusions = settings.getStringArray(exclusionsProperty);
String[] globalExclusions = config.getStringArray(globalExclusionsProperty);
String[] exclusions = config.getStringArray(exclusionsProperty);
return Stream.concat(Arrays.stream(globalExclusions), Arrays.stream(exclusions))
.map(StringUtils::trim)
.toArray(String[]::new);

+ 3
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java Voir le fichier

@@ -25,15 +25,15 @@ import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.internal.charhandler.CharHandler;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.pattern.LineRange;
import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;

public class IssueExclusionsRegexpScanner extends CharHandler {
private static final Logger LOG = LoggerFactory.getLogger(IssueExclusionsLoader.class);
private static final Logger LOG = Loggers.get(IssueExclusionsLoader.class);

private final StringBuilder sb = new StringBuilder();
private final List<Pattern> allFilePatterns;

+ 2
- 24
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractModulePhaseExecutor.java Voir le fichier

@@ -22,17 +22,15 @@ package org.sonar.scanner.phases;
import java.util.Arrays;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.FileIndexer;

public abstract class AbstractModulePhaseExecutor {

@@ -41,26 +39,22 @@ public abstract class AbstractModulePhaseExecutor {
private final PostJobsExecutor postJobsExecutor;
private final SensorsExecutor sensorsExecutor;
private final DefaultModuleFileSystem fs;
private final QProfileVerifier profileVerifier;
private final IssueExclusionsLoader issueExclusionsLoader;
private final InputModuleHierarchy hierarchy;
private final FileIndexer fileIndexer;
private final ModuleCoverageExclusions moduleCoverageExclusions;
private final ProjectCoverageExclusions projectCoverageExclusions;
private final AnalysisWarnings analysisWarnings;
private boolean warnCoverageAlreadyLogged;

public AbstractModulePhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, InputModuleHierarchy hierarchy, DefaultModuleFileSystem fs,
QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, FileIndexer fileIndexer,
IssueExclusionsLoader issueExclusionsLoader,
ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
AnalysisWarnings analysisWarnings) {
this.postJobsExecutor = postJobsExecutor;
this.sensorsExecutor = sensorsExecutor;
this.fs = fs;
this.profileVerifier = profileVerifier;
this.issueExclusionsLoader = issueExclusionsLoader;
this.hierarchy = hierarchy;
this.fileIndexer = fileIndexer;
this.moduleCoverageExclusions = moduleCoverageExclusions;
this.projectCoverageExclusions = projectCoverageExclusions;
this.analysisWarnings = analysisWarnings;
@@ -70,15 +64,6 @@ public abstract class AbstractModulePhaseExecutor {
* Executed on each module
*/
public final void execute(DefaultInputModule module) {
// Index the filesystem
fileIndexer.index();

// Log detected languages and their profiles after FS is indexed and languages detected
profileVerifier.execute();

// Initialize issue exclusions
initIssueExclusions();

// Initialize coverage exclusions
evaluateCoverageExclusions(module);

@@ -133,11 +118,4 @@ public abstract class AbstractModulePhaseExecutor {

protected abstract void executeOnRoot();

private void initIssueExclusions() {
if (issueExclusionsLoader.shouldExecute()) {
for (InputFile inputFile : fs.inputFiles(fs.predicates().all())) {
issueExclusionsLoader.addMulticriteriaPatterns(((DefaultInputFile) inputFile).getModuleRelativePath(), inputFile.key());
}
}
}
}

+ 5
- 7
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/IssuesPhaseExecutor.java Voir le fichier

@@ -25,9 +25,7 @@ import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.issue.tracking.IssueTransition;
import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.report.IssuesReports;

public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor {
@@ -38,11 +36,11 @@ public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor {
private final IssueTransition localIssueTracking;

public IssuesPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy, FileIndexer fileIndexer,
ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
AnalysisWarnings analysisWarnings) {
super(postJobsExecutor, sensorsExecutor, moduleHierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer,
IssuesReports jsonReport, DefaultModuleFileSystem fs,
IssueExclusionsLoader issueExclusionsLoader, IssueTransition localIssueTracking, InputModuleHierarchy moduleHierarchy,
ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
AnalysisWarnings analysisWarnings) {
super(postJobsExecutor, sensorsExecutor, moduleHierarchy, fs, issueExclusionsLoader,
moduleCoverageExclusions, projectCoverageExclusions, analysisWarnings);
this.issuesReport = jsonReport;
this.localIssueTracking = localIssueTracking;

+ 5
- 7
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java Voir le fichier

@@ -24,9 +24,7 @@ import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.scanner.cpd.CpdExecutor;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scm.ScmPublisher;

public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor {
@@ -36,11 +34,11 @@ public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor {
private final ScmPublisher scm;

public PublishPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
ReportPublisher reportPublisher, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader,
CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy, FileIndexer fileIndexer,
ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
AnalysisWarnings analysisWarnings) {
super(postJobsExecutor, sensorsExecutor, hierarchy, fs, profileVerifier, issueExclusionsLoader, fileIndexer, moduleCoverageExclusions,
ReportPublisher reportPublisher, DefaultModuleFileSystem fs, IssueExclusionsLoader issueExclusionsLoader,
CpdExecutor cpdExecutor, ScmPublisher scm, InputModuleHierarchy hierarchy,
ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
AnalysisWarnings analysisWarnings) {
super(postJobsExecutor, sensorsExecutor, hierarchy, fs, issueExclusionsLoader, moduleCoverageExclusions,
projectCoverageExclusions, analysisWarnings);
this.reportPublisher = reportPublisher;
this.cpdExecutor = cpdExecutor;

+ 9
- 11
sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfileVerifier.java Voir le fichier

@@ -23,25 +23,23 @@ import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.scan.filesystem.InputComponentStore;

import static org.apache.commons.lang.StringUtils.isNotEmpty;

@ScannerSide
public class QProfileVerifier {

private static final Logger LOG = LoggerFactory.getLogger(QProfileVerifier.class);

private final Configuration settings;
private final FileSystem fs;
private final Configuration config;
private final InputComponentStore store;
private final QualityProfiles profiles;

public QProfileVerifier(Configuration settings, FileSystem fs, QualityProfiles profiles) {
this.settings = settings;
this.fs = fs;
public QProfileVerifier(Configuration config, InputComponentStore store, QualityProfiles profiles) {
this.config = config;
this.store = store;
this.profiles = profiles;
}

@@ -51,9 +49,9 @@ public class QProfileVerifier {

@VisibleForTesting
void execute(Logger logger) {
String defaultName = settings.get(QualityProfiles.SONAR_PROFILE_PROP).orElse(null);
String defaultName = config.get(QualityProfiles.SONAR_PROFILE_PROP).orElse(null);
boolean defaultNameUsed = StringUtils.isBlank(defaultName);
for (String lang : fs.languages()) {
for (String lang : store.getLanguages()) {
QProfile profile = profiles.findByLanguage(lang);
if (profile == null) {
logger.warn("No Quality profile found for language {}", lang);
@@ -64,7 +62,7 @@ public class QProfileVerifier {
}
}
}
if (!defaultNameUsed && !fs.languages().isEmpty()) {
if (!defaultNameUsed && !store.getLanguages().isEmpty()) {
throw MessageException.of("sonar.profile was set to '" + defaultName + "' but didn't match any profile for any language. Please check your configuration.");
}
}

+ 0
- 25
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ModuleScanContainer.java Voir le fichier

@@ -22,7 +22,6 @@ package org.sonar.scanner.scan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.scan.filesystem.FileExclusions;
import org.sonar.core.extension.CoreExtensionsInstaller;
import org.sonar.core.platform.ComponentContainer;
@@ -33,12 +32,6 @@ import org.sonar.scanner.bootstrap.ScannerExtensionDictionnary;
import org.sonar.scanner.deprecated.perspectives.ScannerPerspectives;
import org.sonar.scanner.issue.ModuleIssueFilters;
import org.sonar.scanner.issue.ModuleIssues;
import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.phases.AbstractModulePhaseExecutor;
import org.sonar.scanner.phases.IssuesPhaseExecutor;
import org.sonar.scanner.phases.ModuleCoverageExclusions;
@@ -49,10 +42,6 @@ import org.sonar.scanner.postjob.DefaultPostJobContext;
import org.sonar.scanner.postjob.PostJobOptimizer;
import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.ExclusionFilters;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.filesystem.InputFileBuilder;
import org.sonar.scanner.scan.filesystem.MetadataGenerator;
import org.sonar.scanner.scan.filesystem.ModuleInputComponentStore;
import org.sonar.scanner.scan.report.IssuesReports;
import org.sonar.scanner.sensor.DefaultSensorContext;
@@ -105,13 +94,7 @@ public class ModuleScanContainer extends ComponentContainer {
// file system
ModuleInputComponentStore.class,
FileExclusions.class,
ExclusionFilters.class,
MetadataGenerator.class,
FileMetadata.class,
FileIndexer.class,
InputFileBuilder.class,
DefaultModuleFileSystem.class,
QProfileVerifier.class,

SensorOptimizer.class,
PostJobOptimizer.class,
@@ -126,14 +109,6 @@ public class ModuleScanContainer extends ComponentContainer {
// issues
ModuleIssues.class,

// issue exclusions
IssueInclusionPatternInitializer.class,
IssueExclusionPatternInitializer.class,
PatternMatcher.class,
IssueExclusionsLoader.class,
EnforceIssuesFilter.class,
IgnoreIssuesFilter.class,

// Perspectives
ScannerPerspectives.class,


+ 32
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java Voir le fichier

@@ -22,6 +22,7 @@ package org.sonar.scanner.scan;
import com.google.common.annotations.VisibleForTesting;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.api.batch.rule.CheckFactory;
@@ -50,6 +51,12 @@ import org.sonar.scanner.deprecated.test.TestPlanBuilder;
import org.sonar.scanner.deprecated.test.TestableBuilder;
import org.sonar.scanner.issue.DefaultProjectIssues;
import org.sonar.scanner.issue.IssueCache;
import org.sonar.scanner.issue.ignore.EnforceIssuesFilter;
import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter;
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer;
import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.issue.tracking.DefaultServerLineHashesLoader;
import org.sonar.scanner.issue.tracking.IssueTransition;
import org.sonar.scanner.issue.tracking.LocalIssueTracking;
@@ -85,6 +92,7 @@ import org.sonar.scanner.rule.ActiveRulesLoader;
import org.sonar.scanner.rule.ActiveRulesProvider;
import org.sonar.scanner.rule.DefaultActiveRulesLoader;
import org.sonar.scanner.rule.DefaultRulesLoader;
import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.rule.RulesLoader;
import org.sonar.scanner.rule.RulesProvider;
import org.sonar.scanner.scan.branch.BranchConfiguration;
@@ -92,8 +100,12 @@ import org.sonar.scanner.scan.branch.BranchConfigurationProvider;
import org.sonar.scanner.scan.branch.BranchType;
import org.sonar.scanner.scan.branch.ProjectBranchesProvider;
import org.sonar.scanner.scan.branch.ProjectPullRequestsProvider;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.scan.filesystem.LanguageDetection;
import org.sonar.scanner.scan.filesystem.MetadataGenerator;
import org.sonar.scanner.scan.filesystem.ProjectExclusionFilters;
import org.sonar.scanner.scan.filesystem.ProjectFileIndexer;
import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator;
import org.sonar.scanner.scan.filesystem.StatusDetection;
import org.sonar.scanner.scan.measure.DefaultMetricFinder;
@@ -165,11 +177,18 @@ public class ProjectScanContainer extends ComponentContainer {
new ScmChangedFilesProvider(),
StatusDetection.class,
LanguageDetection.class,
MetadataGenerator.class,
FileMetadata.class,
FileIndexer.class,
ProjectFileIndexer.class,
ProjectExclusionFilters.class,


// rules
new ActiveRulesProvider(),
new QualityProfilesProvider(),
CheckFactory.class,
QProfileVerifier.class,

// issues
IssueCache.class,
@@ -191,6 +210,14 @@ public class ProjectScanContainer extends ComponentContainer {
// Measures
MeasureCache.class,

// issue exclusions
IssueInclusionPatternInitializer.class,
IssueExclusionPatternInitializer.class,
PatternMatcher.class,
IssueExclusionsLoader.class,
EnforceIssuesFilter.class,
IgnoreIssuesFilter.class,

// context
ContextPropertiesCache.class,
ContextPropertiesPublisher.class,
@@ -290,6 +317,11 @@ public class ProjectScanContainer extends ComponentContainer {
LOG.info("Branch name: {}, type: {}", branchConfig.branchName(), branchTypeToDisplayName(branchConfig.branchType()));
}

getComponentByType(ProjectFileIndexer.class).index();

// Log detected languages and their profiles after FS is indexed and languages detected
getComponentByType(QProfileVerifier.class).execute();

LOG.debug("Start recursive analysis of project modules");
scanRecursively(tree, tree.root(), analysisMode);


+ 171
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java Voir le fichier

@@ -0,0 +1,171 @@
/*
* SonarQube
* Copyright (C) 2009-2018 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.scanner.scan.filesystem;

import java.nio.file.Path;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Stream;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.PathPattern;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;

public abstract class AbstractExclusionFilters {

private static final Logger LOG = Loggers.get(AbstractExclusionFilters.class);
private final String[] sourceInclusions;
private final String[] testInclusions;
private final String[] sourceExclusions;
private final String[] testExclusions;

private PathPattern[] mainInclusionsPattern;
private PathPattern[] mainExclusionsPattern;
private PathPattern[] testInclusionsPattern;
private PathPattern[] testExclusionsPattern;

public AbstractExclusionFilters(Function<String, String[]> configProvider) {
this.sourceInclusions = inclusions(configProvider, CoreProperties.PROJECT_INCLUSIONS_PROPERTY);
this.testInclusions = inclusions(configProvider, CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY);
this.sourceExclusions = exclusions(configProvider, CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_EXCLUSIONS_PROPERTY);
this.testExclusions = exclusions(configProvider, CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY, CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY);
this.mainInclusionsPattern = prepareMainInclusions(sourceInclusions);
this.mainExclusionsPattern = prepareMainExclusions(sourceExclusions, testInclusions);
this.testInclusionsPattern = prepareTestInclusions(testInclusions);
this.testExclusionsPattern = prepareTestExclusions(testExclusions);
}

protected void log() {
log("Included sources: ", mainInclusionsPattern);
log("Excluded sources: ", mainExclusionsPattern);
log("Included tests: ", testInclusionsPattern);
log("Excluded tests: ", testExclusionsPattern);
}

private String[] inclusions(Function<String, String[]> configProvider, String propertyKey) {
return Arrays.stream(configProvider.apply(propertyKey))
.map(StringUtils::trim)
.filter(s -> !"**/*".equals(s))
.filter(s -> !"file:**/*".equals(s))
.toArray(String[]::new);
}

private String[] exclusions(Function<String, String[]> configProvider, String globalExclusionsProperty, String exclusionsProperty) {
String[] globalExclusions = configProvider.apply(globalExclusionsProperty);
String[] exclusions = configProvider.apply(exclusionsProperty);
return Stream.concat(Arrays.stream(globalExclusions), Arrays.stream(exclusions))
.map(StringUtils::trim)
.toArray(String[]::new);
}

public boolean hasPattern() {
return mainInclusionsPattern.length > 0 || mainExclusionsPattern.length > 0 || testInclusionsPattern.length > 0 || testExclusionsPattern.length > 0;
}

private static void log(String title, PathPattern[] patterns) {
if (patterns.length > 0) {
LOG.info(title);
for (PathPattern pattern : patterns) {
LOG.info(" {}", pattern);
}
}
}

public boolean accept(Path absolutePath, Path relativePath, InputFile.Type type) {
PathPattern[] inclusionPatterns;
PathPattern[] exclusionPatterns;
if (InputFile.Type.MAIN == type) {
inclusionPatterns = mainInclusionsPattern;
exclusionPatterns = mainExclusionsPattern;
} else if (InputFile.Type.TEST == type) {
inclusionPatterns = testInclusionsPattern;
exclusionPatterns = testExclusionsPattern;
} else {
throw new IllegalArgumentException("Unknown file type: " + type);
}

if (inclusionPatterns.length > 0) {
boolean matchInclusion = false;
for (PathPattern pattern : inclusionPatterns) {
matchInclusion |= pattern.match(absolutePath, relativePath);
}
if (!matchInclusion) {
return false;
}
}
if (exclusionPatterns.length > 0) {
for (PathPattern pattern : exclusionPatterns) {
if (pattern.match(absolutePath, relativePath)) {
return false;
}
}
}
return true;
}

private static PathPattern[] prepareMainInclusions(String[] sourceInclusions) {
if (sourceInclusions.length > 0) {
// User defined params
return PathPattern.create(sourceInclusions);
}
return new PathPattern[0];
}

private static PathPattern[] prepareTestInclusions(String[] testInclusions) {
return PathPattern.create(testInclusions);
}

static PathPattern[] prepareMainExclusions(String[] sourceExclusions, String[] testInclusions) {
String[] patterns = (String[]) ArrayUtils.addAll(
sourceExclusions, testInclusions);
return PathPattern.create(patterns);
}

private static PathPattern[] prepareTestExclusions(String[] testExclusions) {
return PathPattern.create(testExclusions);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof AbstractExclusionFilters)) {
return false;
}
AbstractExclusionFilters that = (AbstractExclusionFilters) o;
return Arrays.equals(sourceInclusions, that.sourceInclusions) &&
Arrays.equals(testInclusions, that.testInclusions) &&
Arrays.equals(sourceExclusions, that.sourceExclusions) &&
Arrays.equals(testExclusions, that.testExclusions);
}

@Override
public int hashCode() {
int result = Arrays.hashCode(sourceInclusions);
result = 31 * result + Arrays.hashCode(testInclusions);
result = 31 * result + Arrays.hashCode(sourceExclusions);
result = 31 * result + Arrays.hashCode(testExclusions);
return result;
}
}

+ 0
- 132
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ExclusionFilters.java Voir le fichier

@@ -1,132 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.scanner.scan.filesystem;

import java.nio.file.Path;
import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.PathPattern;
import org.sonar.api.scan.filesystem.FileExclusions;

@ScannerSide
public class ExclusionFilters {

private static final Logger LOG = LoggerFactory.getLogger(ExclusionFilters.class);

private final FileExclusions exclusionSettings;

private PathPattern[] mainInclusions;
private PathPattern[] mainExclusions;
private PathPattern[] testInclusions;
private PathPattern[] testExclusions;

public ExclusionFilters(FileExclusions exclusions) {
this.exclusionSettings = exclusions;
}

public void prepare() {
mainInclusions = prepareMainInclusions();
mainExclusions = prepareMainExclusions();
testInclusions = prepareTestInclusions();
testExclusions = prepareTestExclusions();
log("Included sources: ", mainInclusions);
log("Excluded sources: ", mainExclusions);
log("Included tests: ", testInclusions);
log("Excluded tests: ", testExclusions);
}

public boolean hasPattern() {
return mainInclusions.length > 0 || mainExclusions.length > 0 || testInclusions.length > 0 || testExclusions.length > 0;
}

private static void log(String title, PathPattern[] patterns) {
if (patterns.length > 0) {
LOG.info(title);
for (PathPattern pattern : patterns) {
LOG.info(" {}", pattern);
}
}
}

public boolean accept(Path absolutePath, Path relativePath, InputFile.Type type) {
PathPattern[] inclusionPatterns;
PathPattern[] exclusionPatterns;
if (InputFile.Type.MAIN == type) {
inclusionPatterns = mainInclusions;
exclusionPatterns = mainExclusions;
} else if (InputFile.Type.TEST == type) {
inclusionPatterns = testInclusions;
exclusionPatterns = testExclusions;
} else {
throw new IllegalArgumentException("Unknown file type: " + type);
}

if (inclusionPatterns.length > 0) {
boolean matchInclusion = false;
for (PathPattern pattern : inclusionPatterns) {
matchInclusion |= pattern.match(absolutePath, relativePath);
}
if (!matchInclusion) {
return false;
}
}
if (exclusionPatterns.length > 0) {
for (PathPattern pattern : exclusionPatterns) {
if (pattern.match(absolutePath, relativePath)) {
return false;
}
}
}
return true;
}

PathPattern[] prepareMainInclusions() {
if (exclusionSettings.sourceInclusions().length > 0) {
// User defined params
return PathPattern.create(exclusionSettings.sourceInclusions());
}
return new PathPattern[0];
}

PathPattern[] prepareTestInclusions() {
return PathPattern.create(computeTestInclusions());
}

private String[] computeTestInclusions() {
if (exclusionSettings.testInclusions().length > 0) {
// User defined params
return exclusionSettings.testInclusions();
}
return ArrayUtils.EMPTY_STRING_ARRAY;
}

PathPattern[] prepareMainExclusions() {
String[] patterns = (String[]) ArrayUtils.addAll(
exclusionSettings.sourceExclusions(), computeTestInclusions());
return PathPattern.create(patterns);
}

PathPattern[] prepareTestExclusions() {
return PathPattern.create(exclusionSettings.testExclusions());
}
}

+ 91
- 204
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java Voir le fichier

@@ -19,181 +19,136 @@
*/
package org.sonar.scanner.scan.filesystem;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.io.IOException;
import java.nio.file.FileSystemLoopException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.InputFileFilter;
import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.scan.ScanProperties;
import org.sonar.scanner.util.ProgressReport;

/**
* Index input files into {@link InputComponentStore}.
*/
@ScannerSide
public class FileIndexer {

private static final Logger LOG = LoggerFactory.getLogger(FileIndexer.class);
private static final Logger LOG = Loggers.get(FileIndexer.class);
private final AnalysisWarnings analysisWarnings;
private final ScanProperties properties;
private final InputFileFilter[] filters;
private final ExclusionFilters exclusionFilters;
private final InputFileBuilder inputFileBuilder;
private final DefaultInputModule module;
private final ProjectExclusionFilters projectExclusionFilters;
private final IssueExclusionsLoader issueExclusionsLoader;
private final MetadataGenerator metadataGenerator;
private final DefaultInputProject project;
private final ScannerComponentIdGenerator scannerComponentIdGenerator;
private final InputComponentStore componentStore;
private ExecutorService executorService;
private final List<Future<Void>> tasks;
private final DefaultModuleFileSystem defaultModuleFileSystem;
private final SensorStrategy sensorStrategy;
private final LanguageDetection langDetection;

private ProgressReport progressReport;
private boolean warnExclusionsAlreadyLogged;

public FileIndexer(ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, DefaultInputModule module, ExclusionFilters exclusionFilters,
InputFileBuilder inputFileBuilder, DefaultModuleFileSystem defaultModuleFileSystem,
LanguageDetection languageDetection,
InputFileFilter[] filters) {
public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters,
IssueExclusionsLoader issueExclusionsLoader,
MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy,
LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties,
InputFileFilter[] filters) {
this.project = project;
this.scannerComponentIdGenerator = scannerComponentIdGenerator;
this.componentStore = componentStore;
this.module = module;
this.inputFileBuilder = inputFileBuilder;
this.defaultModuleFileSystem = defaultModuleFileSystem;
this.issueExclusionsLoader = issueExclusionsLoader;
this.metadataGenerator = metadataGenerator;
this.sensorStrategy = sensorStrategy;
this.langDetection = languageDetection;
this.analysisWarnings = analysisWarnings;
this.properties = properties;
this.filters = filters;
this.exclusionFilters = exclusionFilters;
this.tasks = new ArrayList<>();
this.projectExclusionFilters = projectExclusionFilters;
}

public FileIndexer(ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, DefaultInputModule module, ExclusionFilters exclusionFilters,
InputFileBuilder inputFileBuilder, DefaultModuleFileSystem defaultModuleFileSystem,
LanguageDetection languageDetection) {
this(scannerComponentIdGenerator, componentStore, module, exclusionFilters, inputFileBuilder, defaultModuleFileSystem, languageDetection,
new InputFileFilter[0]);
public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore, ProjectExclusionFilters projectExclusionFilters,
IssueExclusionsLoader issueExclusionsLoader,
MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, issueExclusionsLoader, metadataGenerator, sensorStrategy, languageDetection, analysisWarnings,
properties, new InputFileFilter[0]);
}

public void index() {
int threads = Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
this.executorService = Executors.newFixedThreadPool(threads, new ThreadFactoryBuilder()
.setNameFormat("FileIndexer-%d")
.setDaemon(true)
.build());

progressReport = new ProgressReport("Report about progress of file indexation", TimeUnit.SECONDS.toMillis(10));
progressReport.start("Index files");
exclusionFilters.prepare();

Progress progress = new Progress();

indexFiles(module.getSourceDirsOrFiles(), InputFile.Type.MAIN, progress);
indexFiles(module.getTestDirsOrFiles(), InputFile.Type.TEST, progress);

waitForTasksToComplete(progressReport);

progressReport.stop(progress.count() + " " + pluralizeFiles(progress.count()) + " indexed");

if (exclusionFilters.hasPattern()) {
LOG.info("{} {} ignored because of inclusion/exclusion patterns", progress.excludedByPatternsCount(), pluralizeFiles(progress.excludedByPatternsCount()));
}
}

private void waitForTasksToComplete(ProgressReport report) {
executorService.shutdown();
for (Future<Void> task : tasks) {
try {
task.get();
} catch (ExecutionException e) {
// Unwrap ExecutionException
stopAsap(report);
throw e.getCause() instanceof RuntimeException ? (RuntimeException) e.getCause() : new IllegalStateException(e.getCause());
} catch (InterruptedException e) {
stopAsap(report);
throw new IllegalStateException(e);
}
}
}

private void stopAsap(ProgressReport report) {
report.stop(null);
executorService.shutdownNow();
try {
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e1) {
// ignore, what's important is the original exception
}
}

private static String pluralizeFiles(int count) {
return count == 1 ? "file" : "files";
}

private void indexFiles(List<Path> sources, InputFile.Type type, Progress progress) {
try {
for (Path dirOrFile : sources) {
if (dirOrFile.toFile().isDirectory()) {
indexDirectory(dirOrFile, type, progress);
} else {
tasks.add(executorService.submit(() -> indexFile(dirOrFile, type, progress)));
}
}
} catch (IOException e) {
throw new IllegalStateException("Failed to index files", e);
}
}

private void indexDirectory(Path dirToIndex, InputFile.Type type, Progress progress) throws IOException {
Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
new IndexFileVisitor(type, progress));
}

private Void indexFile(Path sourceFile, InputFile.Type type, Progress progress) throws IOException {
public void indexFile(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Path sourceFile, InputFile.Type type, ProgressReport progressReport,
AtomicInteger excludedByPatternsCount)
throws IOException {
// get case of real file without resolving link
Path realAbsoluteFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS).toAbsolutePath().normalize();
if (!realAbsoluteFile.startsWith(module.getBaseDir())) {
LOG.warn("File '{}' is ignored. It is not located in module basedir '{}'.", realAbsoluteFile.toAbsolutePath(), module.getBaseDir());
return null;
if (!realAbsoluteFile.startsWith(project.getBaseDir())) {
LOG.warn("File '{}' is ignored. It is not located in project basedir '{}'.", realAbsoluteFile.toAbsolutePath(), project.getBaseDir());
return;
}
Path relativePath = module.getBaseDir().relativize(realAbsoluteFile);
if (!exclusionFilters.accept(realAbsoluteFile, relativePath, type)) {
progress.increaseExcludedByPatternsCount();
return null;
Path projectRelativePath = project.getBaseDir().relativize(realAbsoluteFile);
Path moduleRelativePath = module.getBaseDir().relativize(realAbsoluteFile);
if (!projectExclusionFilters.accept(realAbsoluteFile, projectRelativePath, type)) {
excludedByPatternsCount.incrementAndGet();
return;
}
if (!moduleExclusionFilters.accept(realAbsoluteFile, moduleRelativePath, type)) {
if (projectExclusionFilters.equals(moduleExclusionFilters)) {
warnOnce("File '" + projectRelativePath + "' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
"Please update file inclusion/exclusion configuration so that patterns refer to project relative paths.");
} else {
warnOnce("Defining inclusion/exclusions at module level is deprecated. " +
"Move file inclusion/exclusion configuration from module '" + module.getName() + "' " +
"to the root project and update patterns to refer to project relative paths.");
}
excludedByPatternsCount.incrementAndGet();
return;
}
String language = langDetection.language(realAbsoluteFile, relativePath);
String language = langDetection.language(realAbsoluteFile, projectRelativePath);
if (language == null && langDetection.getForcedLanguage() != null) {
LOG.warn("File '{}' is ignored because it doesn't belong to the forced language '{}'", realAbsoluteFile.toAbsolutePath(), langDetection.getForcedLanguage());
return null;
return;
}
DefaultIndexedFile indexedFile = new DefaultIndexedFile(realAbsoluteFile, project.key(),
projectRelativePath.toString(),
moduleRelativePath.toString(),
type, language, scannerComponentIdGenerator.getAsInt(), sensorStrategy);
DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(module.getKeyWithBranch(), f, module.getEncoding()));
if (language != null) {
inputFile.setPublished(true);
}
DefaultInputFile inputFile = inputFileBuilder.create(type, realAbsoluteFile, language);
if (!accept(inputFile)) {
progress.increaseExcludedByPatternsCount();
return null;
return;
}
if (componentStore.getFile(inputFile.getProjectRelativePath()) != null) {
throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
+ "disjoint sets for main and test files");
}
synchronized (this) {
progress.markAsIndexed(inputFile);
defaultModuleFileSystem.add(inputFile);
componentStore.put(module.key(), inputFile);
if (issueExclusionsLoader.shouldExecute()) {
issueExclusionsLoader.addMulticriteriaPatterns(inputFile.getProjectRelativePath(), inputFile.key());
}
LOG.debug("'{}' indexed {}with language '{}'", projectRelativePath, type == Type.TEST ? "as test " : "", inputFile.language());
if (properties.preloadFileMetadata()) {
inputFile.checkMetadata();
}
int count = componentStore.allFiles().size();
progressReport.message(count + " " + pluralizeFiles(count) + " indexed... (last one was " + inputFile.getProjectRelativePath() + ")");
}

private void warnOnce(String msg) {
if (!warnExclusionsAlreadyLogged) {
LOG.warn(msg);
analysisWarnings.addUnique(msg);
warnExclusionsAlreadyLogged = true;
}
LOG.debug("'{}' indexed {}with language '{}'", relativePath, type == Type.TEST ? "as test " : "", inputFile.language());
inputFileBuilder.checkMetadata(inputFile);
return null;
}

private boolean accept(InputFile indexedFile) {
@@ -207,76 +162,8 @@ public class FileIndexer {
return true;
}

private class IndexFileVisitor implements FileVisitor<Path> {
private final Progress status;
private final Type type;

IndexFileVisitor(InputFile.Type type, Progress status) {
this.status = status;
this.type = type;
}

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
Path fileName = dir.getFileName();

if (fileName != null && fileName.toString().length() > 1 && fileName.toString().charAt(0) == '.') {
return FileVisitResult.SKIP_SUBTREE;
}
if (Files.isHidden(dir)) {
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!Files.isHidden(file)) {
tasks.add(executorService.submit(() -> indexFile(file, type, status)));
}
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
if (exc instanceof FileSystemLoopException) {
LOG.warn("Not indexing due to symlink loop: {}", file.toFile());
return FileVisitResult.CONTINUE;
}

throw exc;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
}

private class Progress {
private AtomicInteger indexedCount = new AtomicInteger(0);
private AtomicInteger excludedByPatternsCount = new AtomicInteger(0);

void markAsIndexed(DefaultInputFile inputFile) {
if (componentStore.getFile(inputFile.getProjectRelativePath()) != null) {
throw MessageException.of("File " + inputFile + " can't be indexed twice. Please check that inclusion/exclusion patterns produce "
+ "disjoint sets for main and test files");
}
int count = indexedCount.incrementAndGet();
progressReport.message(count + " " + pluralizeFiles(count) + " indexed... (last one was " + inputFile.getProjectRelativePath() + ")");
}

void increaseExcludedByPatternsCount() {
excludedByPatternsCount.incrementAndGet();
}

public int excludedByPatternsCount() {
return excludedByPatternsCount.get();
}

int count() {
return indexedCount.get();
}
private static String pluralizeFiles(int count) {
return count == 1 ? "file" : "files";
}

}

+ 2
- 5
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java Voir le fichier

@@ -37,7 +37,6 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileExtensionPredicate;
import org.sonar.api.scanner.fs.InputProject;
import org.sonar.scanner.scan.branch.BranchConfiguration;

/**
@@ -55,11 +54,9 @@ public class InputComponentStore {
private final Map<String, InputComponent> inputComponents = new HashMap<>();
private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create();
private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
private final InputProject project;
private final BranchConfiguration branchConfiguration;

public InputComponentStore(InputProject project, BranchConfiguration branchConfiguration) {
this.project = project;
public InputComponentStore(BranchConfiguration branchConfiguration) {
this.branchConfiguration = branchConfiguration;
}

@@ -83,7 +80,7 @@ public class InputComponentStore {
::iterator;
}

public Iterable<InputFile> allFiles() {
public Collection<InputFile> allFiles() {
return globalInputFileCache.values();
}


+ 0
- 71
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java Voir le fichier

@@ -1,71 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.scanner.scan.filesystem;

import java.nio.file.Path;
import javax.annotation.Nullable;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.scanner.scan.ScanProperties;

public class InputFileBuilder {
private final DefaultInputProject project;
private final DefaultInputModule module;
private final ScannerComponentIdGenerator idGenerator;
private final MetadataGenerator metadataGenerator;
private final boolean preloadMetadata;
private final Path projectBaseDir;
private final SensorStrategy sensorStrategy;

public InputFileBuilder(DefaultInputProject project, DefaultInputModule module, MetadataGenerator metadataGenerator,
ScannerComponentIdGenerator idGenerator, ScanProperties properties,
SensorStrategy sensorStrategy) {
this.sensorStrategy = sensorStrategy;
this.projectBaseDir = project.getBaseDir();
this.project = project;
this.module = module;
this.metadataGenerator = metadataGenerator;
this.idGenerator = idGenerator;
this.preloadMetadata = properties.preloadFileMetadata();
}

DefaultInputFile create(InputFile.Type type, Path absolutePath, @Nullable String language) {
DefaultIndexedFile indexedFile = new DefaultIndexedFile(absolutePath, project.key(),
projectBaseDir.relativize(absolutePath).toString(),
module.getBaseDir().relativize(absolutePath).toString(),
type, language, idGenerator.getAsInt(), sensorStrategy);
DefaultInputFile inputFile = new DefaultInputFile(indexedFile, f -> metadataGenerator.setMetadata(f, module.getEncoding()));
if (language != null) {
inputFile.setPublished(true);
}

return inputFile;
}

void checkMetadata(DefaultInputFile inputFile) {
if (preloadMetadata) {
inputFile.checkMetadata();
}
}
}

+ 7
- 10
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/MetadataGenerator.java Voir le fichier

@@ -22,17 +22,16 @@ package org.sonar.scanner.scan.filesystem;
import com.google.common.annotations.VisibleForTesting;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.fs.internal.Metadata;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;

public class MetadataGenerator {
private static final Logger LOG = LoggerFactory.getLogger(MetadataGenerator.class);
private static final Logger LOG = Loggers.get(MetadataGenerator.class);
@VisibleForTesting
static final Charset UTF_32BE = Charset.forName("UTF-32BE");

@@ -41,11 +40,9 @@ public class MetadataGenerator {

private final StatusDetection statusDetection;
private final FileMetadata fileMetadata;
private final DefaultInputModule inputModule;
private final IssueExclusionsLoader exclusionsScanner;

public MetadataGenerator(DefaultInputModule inputModule, StatusDetection statusDetection, FileMetadata fileMetadata, IssueExclusionsLoader exclusionsScanner) {
this.inputModule = inputModule;
public MetadataGenerator(StatusDetection statusDetection, FileMetadata fileMetadata, IssueExclusionsLoader exclusionsScanner) {
this.statusDetection = statusDetection;
this.fileMetadata = fileMetadata;
this.exclusionsScanner = exclusionsScanner;
@@ -55,7 +52,7 @@ public class MetadataGenerator {
* Sets all metadata in the file, including charset and status.
* It is an expensive computation, reading the entire file.
*/
public void setMetadata(final DefaultInputFile inputFile, Charset defaultEncoding) {
public void setMetadata(String moduleKeyWithBranch, final DefaultInputFile inputFile, Charset defaultEncoding) {
CharsetDetector charsetDetector = new CharsetDetector(inputFile.path(), defaultEncoding);
try {
Charset charset;
@@ -69,8 +66,8 @@ public class MetadataGenerator {
inputFile.setCharset(charset);
Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile.key()));
inputFile.setMetadata(metadata);
inputFile.setStatus(statusDetection.status(inputModule.definition().getKeyWithBranch(), inputFile, metadata.hash()));
LOG.debug("'{}' generated metadata {} with charset '{}'", inputFile, inputFile.type() == Type.TEST ? "as test " : "", charset);
inputFile.setStatus(statusDetection.status(moduleKeyWithBranch, inputFile, metadata.hash()));
LOG.debug("'{}' generated metadata{} with charset '{}'", inputFile, inputFile.type() == Type.TEST ? " as test " : "", charset);
} catch (Exception e) {
throw new IllegalStateException(e);
}

+ 35
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleExclusionFilters.java Voir le fichier

@@ -0,0 +1,35 @@
/*
* SonarQube
* Copyright (C) 2009-2018 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.scanner.scan.filesystem;

import org.sonar.api.batch.fs.internal.DefaultInputModule;

import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv;

public class ModuleExclusionFilters extends AbstractExclusionFilters {

public ModuleExclusionFilters(DefaultInputModule module) {
super(k -> {
String value = module.properties().get(k);
return value != null ? parseAsCsv(k, value) : new String[0];
});
}

}

+ 31
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFilters.java Voir le fichier

@@ -0,0 +1,31 @@
/*
* SonarQube
* Copyright (C) 2009-2018 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.scanner.scan.filesystem;

import org.sonar.api.config.Configuration;

public class ProjectExclusionFilters extends AbstractExclusionFilters {

public ProjectExclusionFilters(Configuration projectConfig) {
super(projectConfig::getStringArray);
log();
}

}

+ 168
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java Voir le fichier

@@ -0,0 +1,168 @@
/*
* SonarQube
* Copyright (C) 2009-2018 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.scanner.scan.filesystem;

import java.io.IOException;
import java.nio.file.FileSystemLoopException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.scanner.util.ProgressReport;

/**
* Index project input files into {@link InputComponentStore}.
*/
public class ProjectFileIndexer {

private static final Logger LOG = LoggerFactory.getLogger(ProjectFileIndexer.class);
private final AbstractExclusionFilters projectExclusionFilters;
private final DefaultInputProject project;
private final InputComponentStore componentStore;
private final InputModuleHierarchy inputModuleHierarchy;
private final FileIndexer fileIndexer;

private ProgressReport progressReport;

public ProjectFileIndexer(DefaultInputProject project, InputComponentStore componentStore, AbstractExclusionFilters exclusionFilters,
InputModuleHierarchy inputModuleHierarchy,
FileIndexer fileIndexer) {
this.project = project;
this.componentStore = componentStore;
this.inputModuleHierarchy = inputModuleHierarchy;
this.fileIndexer = fileIndexer;
this.projectExclusionFilters = exclusionFilters;
}

public void index() {
progressReport = new ProgressReport("Report about progress of file indexation", TimeUnit.SECONDS.toMillis(10));
progressReport.start("Index files");

AtomicInteger excludedByPatternsCount = new AtomicInteger(0);

indexModulesRecursively(inputModuleHierarchy.root(), excludedByPatternsCount);

int totalIndexed = componentStore.allFiles().size();
progressReport.stop(totalIndexed + " " + pluralizeFiles(totalIndexed) + " indexed");

if (projectExclusionFilters.hasPattern()) {
int excludedFileCount = excludedByPatternsCount.get();
LOG.info("{} {} ignored because of inclusion/exclusion patterns", excludedFileCount, pluralizeFiles(excludedFileCount));
}
}

private void indexModulesRecursively(DefaultInputModule module, AtomicInteger excludedByPatternsCount) {
inputModuleHierarchy.children(module).forEach(m -> indexModulesRecursively(m, excludedByPatternsCount));
index(module, excludedByPatternsCount);
}

private void index(DefaultInputModule module, AtomicInteger excludedByPatternsCount) {
ModuleExclusionFilters moduleExclusionFilters = new ModuleExclusionFilters(module);
indexFiles(module, moduleExclusionFilters, module.getSourceDirsOrFiles(), Type.MAIN, excludedByPatternsCount);
indexFiles(module, moduleExclusionFilters, module.getTestDirsOrFiles(), Type.TEST, excludedByPatternsCount);
}

private static String pluralizeFiles(int count) {
return count == 1 ? "file" : "files";
}

private void indexFiles(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, List<Path> sources, Type type, AtomicInteger excludedByPatternsCount) {
try {
for (Path dirOrFile : sources) {
if (dirOrFile.toFile().isDirectory()) {
indexDirectory(module, moduleExclusionFilters, dirOrFile, type, excludedByPatternsCount);
} else {
fileIndexer.indexFile(module, moduleExclusionFilters, dirOrFile, type, progressReport, excludedByPatternsCount);
}
}
} catch (IOException e) {
throw new IllegalStateException("Failed to index files", e);
}
}

private void indexDirectory(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Path dirToIndex, Type type, AtomicInteger excludedByPatternsCount)
throws IOException {
Files.walkFileTree(dirToIndex.normalize(), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
new IndexFileVisitor(module, moduleExclusionFilters, type, excludedByPatternsCount));
}

private class IndexFileVisitor implements FileVisitor<Path> {
private final DefaultInputModule module;
private final AbstractExclusionFilters moduleExclusionFilters;
private final Type type;
private final AtomicInteger excludedByPatternsCount;

IndexFileVisitor(DefaultInputModule module, AbstractExclusionFilters moduleExclusionFilters, Type type, AtomicInteger excludedByPatternsCount) {
this.module = module;
this.moduleExclusionFilters = moduleExclusionFilters;
this.type = type;
this.excludedByPatternsCount = excludedByPatternsCount;
}

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
Path fileName = dir.getFileName();

if (fileName != null && fileName.toString().length() > 1 && fileName.toString().charAt(0) == '.') {
return FileVisitResult.SKIP_SUBTREE;
}
if (Files.isHidden(dir)) {
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!Files.isHidden(file)) {
fileIndexer.indexFile(module, moduleExclusionFilters, file, type, progressReport, excludedByPatternsCount);
}
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
if (exc instanceof FileSystemLoopException) {
LOG.warn("Not indexing due to symlink loop: {}", file.toFile());
return FileVisitResult.CONTINUE;
}

throw exc;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
}

}

+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java Voir le fichier

@@ -90,7 +90,7 @@ public class CpdExecutorTest {
when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir));

DefaultInputProject project = TestInputFileBuilder.newDefaultInputProject("foo", baseDir);
componentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
componentStore = new InputComponentStore(mock(BranchConfiguration.class));
executor = new CpdExecutor(settings, index, publisher, componentStore, executorService);
reader = new ScannerReportReader(outputDir);


+ 124
- 32
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java Voir le fichier

@@ -37,13 +37,15 @@ import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.mediumtest.LogOutputRecorder;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.xoo.XooPlugin;
import org.sonar.xoo.global.GlobalSensor;
import org.sonar.xoo.rule.XooRulesDefinition;

import static java.util.stream.Collectors.joining;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeTrue;

@@ -55,14 +57,14 @@ public class FileSystemMediumTest {
@Rule
public ExpectedException thrown = ExpectedException.none();

private LogOutputRecorder logs = new LogOutputRecorder();
@Rule
public LogTester logTester = new LogTester();

@Rule
public ScannerMediumTester tester = new ScannerMediumTester()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way")
.addDefaultQProfile("xoo2", "Sonar Way")
.setLogOutput(logs);
.addDefaultQProfile("xoo2", "Sonar Way");

private File baseDir;
private ImmutableMap.Builder<String, String> builder;
@@ -137,9 +139,9 @@ public class FileSystemMediumTest {
.build())
.execute();

assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
assertThat(logs.getAllAsString()).contains("Organization key: my org");
assertThat(logs.getAllAsString()).doesNotContain("Branch key");
assertThat(logTester.logs()).contains("Project key: com.foo.project");
assertThat(logTester.logs()).contains("Organization key: my org");
assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Branch key");
}

@Test
@@ -158,9 +160,9 @@ public class FileSystemMediumTest {
.build())
.execute();

assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
assertThat(logs.getAllAsString()).contains("Branch key: my-branch");
assertThat(logs.getAllAsString()).contains("The use of \"sonar.branch\" is deprecated and replaced by \"sonar.branch.name\".");
assertThat(logTester.logs()).contains("Project key: com.foo.project");
assertThat(logTester.logs()).contains("Branch key: my-branch");
assertThat(logTester.logs()).contains("The use of \"sonar.branch\" is deprecated and replaced by \"sonar.branch.name\". See https://redirect.sonarsource.com/doc/branches.html.");
}

@Test
@@ -197,9 +199,9 @@ public class FileSystemMediumTest {
.build())
.execute();

assertThat(logs.getAllAsString()).contains("Project key: com.foo.project");
assertThat(logs.getAllAsString()).doesNotContain("Organization key");
assertThat(logs.getAllAsString()).doesNotContain("Branch key");
assertThat(logTester.logs()).contains("Project key: com.foo.project");
assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Organization key");
assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("Branch key");
}

@Test
@@ -215,15 +217,17 @@ public class FileSystemMediumTest {
File javaFile = new File(srcDir, "sample.java");
FileUtils.write(javaFile, "Sample xoo\ncontent");

logTester.setLevel(LoggerLevel.DEBUG);

tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();

assertThat(logs.getAllAsString()).contains("2 files indexed");
assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
assertThat(logs.getAllAsString()).doesNotContain("'src/sample.java' generated metadata");
assertThat(logTester.logs()).contains("2 files indexed");
assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/sample.java' generated metadata");

}

@@ -241,15 +245,17 @@ public class FileSystemMediumTest {
File javaFile = new File(srcDir, "sample.java");
FileUtils.write(javaFile, "Sample xoo\ncontent");

logTester.setLevel(LoggerLevel.DEBUG);

tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();

assertThat(logs.getAllAsString()).contains("2 files indexed");
assertThat(logs.getAllAsString()).contains("'src/sample.xoo' generated metadata");
assertThat(logs.getAllAsString()).contains("'src/sample.java' generated metadata");
assertThat(logTester.logs()).contains("2 files indexed");
assertThat(logTester.logs()).contains("'src/sample.xoo' generated metadata with charset 'UTF-8'");
assertThat(logTester.logs()).contains("'src/sample.java' generated metadata with charset 'UTF-8'");
}

@Test
@@ -271,6 +277,8 @@ public class FileSystemMediumTest {
Path javaFile = mainDir.resolve("sample.java");
Files.write(javaFile, "Sample xoo\ncontent".getBytes(StandardCharsets.UTF_8));

logTester.setLevel(LoggerLevel.DEBUG);

AnalysisResult result = tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src/main")
@@ -278,10 +286,10 @@ public class FileSystemMediumTest {
.build())
.execute();

assertThat(logs.getAllAsString()).contains("3 files indexed");
assertThat(logs.getAllAsString()).contains("'src/main/sample.xoo' generated metadata");
assertThat(logs.getAllAsString()).doesNotContain("'src/main/sample.java' generated metadata");
assertThat(logs.getAllAsString()).doesNotContain("'src/test/sample.java' generated metadata");
assertThat(logTester.logs()).contains("3 files indexed");
assertThat(logTester.logs()).contains("'src/main/sample.xoo' generated metadata with charset 'UTF-8'");
assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/main/sample.java' generated metadata");
assertThat(logTester.logs().stream().collect(joining("\n"))).doesNotContain("'src/test/sample.java' generated metadata");
DefaultInputFile javaInputFile = (DefaultInputFile) result.inputFile("src/main/sample.java");

thrown.expect(IllegalStateException.class);
@@ -304,15 +312,17 @@ public class FileSystemMediumTest {
File xooFile = new File(srcDir, "sample.unknown");
FileUtils.write(xooFile, "Sample xoo\ncontent");

logTester.setLevel(LoggerLevel.DEBUG);

AnalysisResult result = tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();

assertThat(logs.getAllAsString()).contains("1 file indexed");
assertThat(logs.getAllAsString()).contains("'src" + File.separator + "sample.unknown' indexed with language 'null'");
assertThat(logs.getAllAsString()).contains("'src/sample.unknown' generated metadata");
assertThat(logTester.logs()).contains("1 file indexed");
assertThat(logTester.logs()).contains("'src" + File.separator + "sample.unknown' indexed with language 'null'");
assertThat(logTester.logs()).contains("'src/sample.unknown' generated metadata with charset 'UTF-8'");
DefaultInputFile inputFile = (DefaultInputFile) result.inputFile("src/sample.unknown");
assertThat(result.getReportComponent(inputFile)).isNotNull();
}
@@ -337,15 +347,17 @@ public class FileSystemMediumTest {
new Random().nextBytes(b);
FileUtils.writeByteArrayToFile(unknownFile, b);

logTester.setLevel(LoggerLevel.DEBUG);

tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();

assertThat(logs.getAllAsString()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with language 'null'");
assertThat(logs.getAllAsString()).doesNotContain("'src/myfile.binary' generating issue exclusions");
assertThat(logs.getAllAsString()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
assertThat(logTester.logs()).containsOnlyOnce("'src" + File.separator + "myfile.binary' indexed with language 'null'");
assertThat(logTester.logs()).doesNotContain("'src/myfile.binary' generating issue exclusions");
assertThat(logTester.logs()).containsOnlyOnce("'src/sample.xoo' generating issue exclusions");
}

@Test
@@ -363,14 +375,16 @@ public class FileSystemMediumTest {
File unknownFile = new File(srcDir, "myfile.binary");
FileUtils.write(unknownFile, "some text");

logTester.setLevel(LoggerLevel.DEBUG);

tester.newAnalysis()
.properties(builder
.put("sonar.sources", "src")
.build())
.execute();

assertThat(logs.getAllAsString()).containsOnlyOnce("- Exclusion pattern 'pattern'");
assertThat(logs.getAllAsString()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
assertThat(logTester.logs()).containsOnlyOnce("- Exclusion pattern 'pattern': every issue in this file will be ignored.");
assertThat(logTester.logs()).containsOnlyOnce("'src/myfile.binary' generating issue exclusions");
}

@Test
@@ -525,6 +539,84 @@ public class FileSystemMediumTest {
assertThat(result.inputFiles()).hasSize(2);
}

@Test
public void warn_user_for_outdated_inherited_exclusions_for_multi_module_project() throws IOException {

File baseDir = temp.getRoot();
File baseDirModuleA = new File(baseDir, "moduleA");
File baseDirModuleB = new File(baseDir, "moduleB");
File srcDirA = new File(baseDirModuleA, "src");
srcDirA.mkdirs();
File srcDirB = new File(baseDirModuleB, "src");
srcDirB.mkdirs();

File xooFileA = new File(srcDirA, "sample.xoo");
FileUtils.write(xooFileA, "Sample xoo\ncontent", StandardCharsets.UTF_8);

File xooFileB = new File(srcDirB, "sample.xoo");
FileUtils.write(xooFileB, "Sample xoo\ncontent", StandardCharsets.UTF_8);

AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.sources", "src")
.put("sonar.modules", "moduleA,moduleB")
.put("sonar.exclusions", "src/sample.xoo")
.build())
.execute();

InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
assertThat(fileA).isNull();

InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
assertThat(fileB).isNull();

assertThat(logTester.logs(LoggerLevel.WARN))
.contains("File 'moduleB/src/sample.xoo' was excluded because patterns are still evaluated using module relative paths but this is deprecated. " +
"Please update file inclusion/exclusion configuration so that patterns refer to project relative paths.");
}

@Test
public void warn_user_for_outdated_module_exclusions_for_multi_module_project() throws IOException {

File baseDir = temp.getRoot();
File baseDirModuleA = new File(baseDir, "moduleA");
File baseDirModuleB = new File(baseDir, "moduleB");
File srcDirA = new File(baseDirModuleA, "src");
srcDirA.mkdirs();
File srcDirB = new File(baseDirModuleB, "src");
srcDirB.mkdirs();

File xooFileA = new File(srcDirA, "sample.xoo");
FileUtils.write(xooFileA, "Sample xoo\ncontent", StandardCharsets.UTF_8);

File xooFileB = new File(srcDirB, "sample.xoo");
FileUtils.write(xooFileB, "Sample xoo\ncontent", StandardCharsets.UTF_8);

AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.sources", "src")
.put("sonar.modules", "moduleA,moduleB")
.put("moduleB.sonar.exclusions", "src/sample.xoo")
.build())
.execute();

InputFile fileA = result.inputFile("moduleA/src/sample.xoo");
assertThat(fileA).isNotNull();

InputFile fileB = result.inputFile("moduleB/src/sample.xoo");
assertThat(fileB).isNull();

assertThat(logTester.logs(LoggerLevel.WARN))
.contains("Defining inclusion/exclusions at module level is deprecated. " +
"Move file inclusion/exclusion configuration from module 'moduleB' to the root project and update patterns to refer to project relative paths.");
}

@Test
public void failForDuplicateInputFile() throws IOException {
File srcDir = new File(baseDir, "src");
@@ -639,7 +731,7 @@ public class FileSystemMediumTest {
.execute();

assertThat(result.inputFiles()).hasSize(4);
assertThat(logs.get("INFO")).contains(
assertThat(logTester.logs(LoggerLevel.INFO)).contains(
"Global Sensor: module_a/module_a1/src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo",
"Global Sensor: module_a/module_a2/src/main/xoo/com/sonar/it/samples/modules/a2/HelloA2.xoo",
"Global Sensor: module_b/module_b1/src/main/xoo/com/sonar/it/samples/modules/b1/HelloB1.xoo",

+ 1
- 3
sonar-scanner-engine/src/test/java/org/sonar/scanner/postjob/DefaultPostJobContextTest.java Voir le fichier

@@ -26,7 +26,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.postjob.issue.PostJobIssue;
import org.sonar.api.batch.rule.Severity;
@@ -54,8 +53,7 @@ public class DefaultPostJobContextTest {
@Before
public void setUp() throws IOException {
issueCache = mock(IssueCache.class);
DefaultInputProject project = TestInputFileBuilder.newDefaultInputProject("foo", temp.newFolder());
componentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
componentStore = new InputComponentStore(mock(BranchConfiguration.class));
settings = new MapSettings();
analysisMode = mock(AnalysisMode.class);
context = new DefaultPostJobContext(settings.asConfig(), settings, issueCache, componentStore, analysisMode);

+ 5
- 5
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java Voir le fichier

@@ -85,7 +85,7 @@ public class ComponentsPublisherTest {
.setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1);

InputComponentStore store = new InputComponentStore(project, branchConfiguration);
InputComponentStore store = new InputComponentStore(branchConfiguration);

Path moduleBaseDir = temp.newFolder().toPath();
ProjectDefinition module1Def = ProjectDefinition.create()
@@ -150,7 +150,7 @@ public class ComponentsPublisherTest {

DefaultInputProject project = new DefaultInputProject(rootDef, 1);

InputComponentStore store = new InputComponentStore(project, branchConfiguration);
InputComponentStore store = new InputComponentStore(branchConfiguration);

ComponentsPublisher publisher = new ComponentsPublisher(project, store);
publisher.publish(writer);
@@ -175,7 +175,7 @@ public class ComponentsPublisherTest {
.setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1);

InputComponentStore store = new InputComponentStore(project, branchConfiguration);
InputComponentStore store = new InputComponentStore(branchConfiguration);

DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.java", 5)
.setLines(2)
@@ -212,7 +212,7 @@ public class ComponentsPublisherTest {
.setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1);

InputComponentStore store = new InputComponentStore(project, branchConfiguration);
InputComponentStore store = new InputComponentStore(branchConfiguration);
ComponentsPublisher publisher = new ComponentsPublisher(project, store);
publisher.publish(writer);

@@ -244,7 +244,7 @@ public class ComponentsPublisherTest {
.setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1);

InputComponentStore store = new InputComponentStore(project, branchConfiguration);
InputComponentStore store = new InputComponentStore(branchConfiguration);
ComponentsPublisher publisher = new ComponentsPublisher(project, store);
publisher.publish(writer);


+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java Voir le fichier

@@ -58,7 +58,7 @@ public class CoveragePublisherTest {
String moduleKey = "foo";
inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setLines(5).build();
DefaultInputProject rootModule = TestInputFileBuilder.newDefaultInputProject(moduleKey, temp.newFolder());
InputComponentStore componentCache = new InputComponentStore(rootModule, mock(BranchConfiguration.class));
InputComponentStore componentCache = new InputComponentStore(mock(BranchConfiguration.class));
componentCache.put(moduleKey, inputFile);

measureCache = mock(MeasureCache.class);

+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java Voir le fichier

@@ -69,7 +69,7 @@ public class MeasuresPublisherTest {
String projectKey = "foo";
project = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder());
inputFile = new TestInputFileBuilder(projectKey, "src/Foo.php").setPublish(true).build();
InputComponentStore componentCache = new InputComponentStore(project, mock(BranchConfiguration.class));
InputComponentStore componentCache = new InputComponentStore(mock(BranchConfiguration.class));
componentCache.put(projectKey, inputFile);
measureCache = mock(MeasureCache.class);
when(measureCache.byComponentKey(anyString())).thenReturn(Collections.<DefaultMeasure<?>>emptyList());

+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java Voir le fichier

@@ -58,7 +58,7 @@ public class SourcePublisherTest {
.build();

DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(moduleKey, baseDir);
InputComponentStore componentStore = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
InputComponentStore componentStore = new InputComponentStore(mock(BranchConfiguration.class));
componentStore.put(moduleKey, inputFile);

publisher = new SourcePublisher(componentStore);

+ 12
- 11
sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java Voir le fichier

@@ -25,10 +25,11 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.MessageException;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.InputComponentStore;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -42,13 +43,13 @@ public class QProfileVerifierTest {
@Rule
public ExpectedException thrown = ExpectedException.none();

private DefaultFileSystem fs;
private InputComponentStore store;
private QualityProfiles profiles;
private MapSettings settings = new MapSettings();

@Before
public void before() throws Exception {
fs = new DefaultFileSystem(temp.newFolder().toPath());
store = new InputComponentStore(mock(BranchConfiguration.class));
profiles = mock(QualityProfiles.class);
QProfile javaProfile = new QProfile("p1", "My Java profile", "java", null);
when(profiles.findByLanguage("java")).thenReturn(javaProfile);
@@ -58,10 +59,10 @@ public class QProfileVerifierTest {

@Test
public void should_log_all_used_profiles() {
fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
fs.add(new TestInputFileBuilder("foo", "src/Baz.cbl").setLanguage("cobol").build());
store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
store.put("foo", new TestInputFileBuilder("foo", "src/Baz.cbl").setLanguage("cobol").build());

QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);
Logger logger = mock(Logger.class);
profileLogger.execute(logger);

@@ -71,11 +72,11 @@ public class QProfileVerifierTest {

@Test
public void should_fail_if_default_profile_not_used() {
fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());

settings.setProperty("sonar.profile", "Unknown");

QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);

thrown.expect(MessageException.class);
thrown.expectMessage("sonar.profile was set to 'Unknown' but didn't match any profile for any language. Please check your configuration.");
@@ -87,7 +88,7 @@ public class QProfileVerifierTest {
public void should_not_fail_if_no_language_on_project() {
settings.setProperty("sonar.profile", "Unknown");

QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);

profileLogger.execute();

@@ -95,11 +96,11 @@ public class QProfileVerifierTest {

@Test
public void should_not_fail_if_default_profile_used_at_least_once() {
fs.add(new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());
store.put("foo", new TestInputFileBuilder("foo", "src/Bar.java").setLanguage("java").build());

settings.setProperty("sonar.profile", "My Java profile");

QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), fs, profiles);
QProfileVerifier profileLogger = new QProfileVerifier(settings.asConfig(), store, profiles);

profileLogger.execute();
}

+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java Voir le fichier

@@ -37,7 +37,7 @@ public class ModuleIndexerTest {
private InputComponentStore componentStore;

public void createIndexer(DefaultInputProject rootProject) {
componentStore = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
componentStore = new InputComponentStore(mock(BranchConfiguration.class));
moduleHierarchy = mock(DefaultInputModuleHierarchy.class);
indexer = new ModuleIndexer(componentStore, moduleHierarchy);
}

+ 2
- 2
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java Voir le fichier

@@ -60,7 +60,7 @@ public class InputComponentStoreTest {
DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(rootDef);
DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(moduleDef);

InputComponentStore store = new InputComponentStore(rootProject, mock(BranchConfiguration.class));
InputComponentStore store = new InputComponentStore(mock(BranchConfiguration.class));
store.put(subModule);

DefaultInputFile fooFile = new TestInputFileBuilder(rootModuleKey, "src/main/java/Foo.java")
@@ -96,7 +96,7 @@ public class InputComponentStoreTest {

static class InputComponentStoreTester extends InputComponentStore {
InputComponentStoreTester() throws IOException {
super(TestInputFileBuilder.newDefaultInputProject("root", temp.newFolder()), mock(BranchConfiguration.class));
super(mock(BranchConfiguration.class));
}

InputFile addFile(String moduleKey, String relpath, String language) {

+ 0
- 91
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputFileBuilderTest.java Voir le fichier

@@ -1,91 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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.scanner.scan.filesystem;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.DefaultInputProject;
import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.scanner.scan.ScanProperties;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

public class InputFileBuilderTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();

private Path baseDir;
private Path workDir;
private InputFileBuilder builder;

private SensorStrategy sensorStrategy;

@Before
public void setUp() throws IOException {
baseDir = temp.newFolder().toPath();
workDir = temp.newFolder().toPath();
DefaultInputProject project = new DefaultInputProject(ProjectDefinition.create()
.setBaseDir(baseDir.toFile())
.setWorkDir(workDir.toFile())
.setProperty(CoreProperties.ENCODING_PROPERTY, StandardCharsets.UTF_8.name())
.setKey("root"), 0);
Path moduleBaseDir = baseDir.resolve("module1");
Files.createDirectories(moduleBaseDir);
DefaultInputModule module = new DefaultInputModule(ProjectDefinition.create()
.setBaseDir(moduleBaseDir.toFile())
.setWorkDir(workDir.toFile())
.setKey("module1"), 1);

MetadataGenerator metadataGenerator = mock(MetadataGenerator.class);
ScannerComponentIdGenerator idGenerator = new ScannerComponentIdGenerator();
ScanProperties properties = mock(ScanProperties.class);
sensorStrategy = new SensorStrategy();
builder = new InputFileBuilder(project, module, metadataGenerator, idGenerator, properties,
sensorStrategy);
}

@Test
public void testBuild() {
Path filePath = baseDir.resolve("module1/src/File1.xoo");
DefaultInputFile inputFile = builder.create(Type.MAIN, filePath, null);

assertThat(inputFile.absolutePath()).isEqualTo(filePath.toString().replaceAll("\\\\", "/"));
assertThat(inputFile.relativePath()).isEqualTo("src/File1.xoo");
assertThat(inputFile.path()).isEqualTo(filePath);
assertThat(inputFile.key()).isEqualTo("root:module1/src/File1.xoo");
assertThat(inputFile.isPublished()).isFalse();

sensorStrategy.setGlobal(true);

assertThat(inputFile.relativePath()).isEqualTo("module1/src/File1.xoo");
}
}

+ 2
- 5
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/MetadataGeneratorTest.java Voir le fichier

@@ -31,10 +31,8 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.utils.PathUtils;
@@ -64,8 +62,7 @@ public class MetadataGeneratorTest {
MockitoAnnotations.initMocks(this);
metadata = new FileMetadata();
IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class));
generator = new MetadataGenerator(new DefaultInputModule(ProjectDefinition.create().setKey("module").setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())),
statusDetection, metadata, issueExclusionsLoader);
generator = new MetadataGenerator(statusDetection, metadata, issueExclusionsLoader);
}

@Test
@@ -94,7 +91,7 @@ public class MetadataGeneratorTest {
DefaultInputFile inputFile = new TestInputFileBuilder("struts", relativePath)
.setModuleBaseDir(baseDir)
.build();
generator.setMetadata(inputFile, StandardCharsets.US_ASCII);
generator.setMetadata("module", inputFile, StandardCharsets.US_ASCII);
return inputFile;
}


+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java Voir le fichier

@@ -49,7 +49,7 @@ public class ModuleInputComponentStoreTest {
@Before
public void setUp() throws IOException {
DefaultInputProject root = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder());
componentStore = new InputComponentStore(root, mock(BranchConfiguration.class));
componentStore = new InputComponentStore(mock(BranchConfiguration.class));
}

@Test

sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ExclusionFiltersTest.java → sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ProjectExclusionFiltersTest.java Voir le fichier

@@ -32,28 +32,25 @@ import org.sonar.api.batch.fs.IndexedFile;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.scan.filesystem.FileExclusions;

import static org.assertj.core.api.Assertions.assertThat;

public class ExclusionFiltersTest {
public class ProjectExclusionFiltersTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();
private Path moduleBaseDir;
private MapSettings settings;
private ExclusionFilters filter;

@Before
public void setUp() throws IOException {
settings = new MapSettings();
moduleBaseDir = temp.newFolder().toPath();
filter = new ExclusionFilters(new FileExclusions(settings.asConfig()));
}

@Test
public void no_inclusions_nor_exclusions() throws IOException {
filter.prepare();
ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());

IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
@@ -63,7 +60,7 @@ public class ExclusionFiltersTest {
@Test
public void match_inclusion() throws IOException {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java");
filter.prepare();
ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());

IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
@@ -75,7 +72,7 @@ public class ExclusionFiltersTest {
@Test
public void match_at_least_one_inclusion() throws IOException {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java,**/*Dto.java");
filter.prepare();
ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());

IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/Foo.java", null);
assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
@@ -89,7 +86,7 @@ public class ExclusionFiltersTest {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
settings.setProperty(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, "src/test/java/**/*");
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.java");
filter.prepare();
ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());

IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/com/mycompany/FooDao.java", null);
assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
@@ -108,7 +105,7 @@ public class ExclusionFiltersTest {

settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getAbsolutePath());
filter.prepare();
ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());

IndexedFile indexedFile = new DefaultIndexedFile("foo", moduleBaseDir, "src/main/java/org/bar/Foo.java", null);
assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
@@ -119,9 +116,9 @@ public class ExclusionFiltersTest {

@Test
public void trim_pattern() {
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, " **/*Dao.java ");
ProjectExclusionFilters filter = new ProjectExclusionFilters(settings.asConfig());

assertThat(filter.prepareMainExclusions()[0].toString()).isEqualTo("**/*Dao.java");
assertThat(filter.prepareMainExclusions(new String[] {" **/*Dao.java "}, new String[0])[0].toString()).isEqualTo("**/*Dao.java");
}

}

+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/report/JSONReportTest.java Voir le fichier

@@ -79,7 +79,7 @@ public class JSONReportTest {

ProjectDefinition def = ProjectDefinition.create().setBaseDir(projectBaseDir).setWorkDir(temp.newFolder()).setKey("struts");
DefaultInputProject project = new DefaultInputProject(def, 1);
InputComponentStore inputComponentStore = new InputComponentStore(project, mock(BranchConfiguration.class));
InputComponentStore inputComponentStore = new InputComponentStore(mock(BranchConfiguration.class));

DefaultInputFile inputFile = new TestInputFileBuilder("struts", "src/main/java/org/apache/struts/Action.java")
.setModuleBaseDir(projectBaseDir.toPath()).build();

Chargement…
Annuler
Enregistrer