Bladeren bron

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

tags/7.6
Julien HENRY 5 jaren geleden
bovenliggende
commit
cc9d2163a0
34 gewijzigde bestanden met toevoegingen van 731 en 677 verwijderingen
  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 Bestand weergeven

package org.sonar.api.batch.fs; package org.sonar.api.batch.fs;


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


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

+ 0
- 4
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/FileMetadata.java Bestand weergeven

import java.io.Reader; import java.io.Reader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;

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

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

+ 7
- 6
sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/FileExclusions.java Bestand weergeven

@Deprecated @Deprecated
@ScannerSide @ScannerSide
public class FileExclusions { 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() { public String[] sourceInclusions() {
} }


private String[] inclusions(String propertyKey) { private String[] inclusions(String propertyKey) {
return Arrays.stream(settings.getStringArray(propertyKey))
return Arrays.stream(config.getStringArray(propertyKey))
.map(StringUtils::trim) .map(StringUtils::trim)
.filter(s -> !"**/*".equals(s)) .filter(s -> !"**/*".equals(s))
.filter(s -> !"file:**/*".equals(s)) .filter(s -> !"file:**/*".equals(s))
} }


private String[] exclusions(String globalExclusionsProperty, String exclusionsProperty) { 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)) return Stream.concat(Arrays.stream(globalExclusions), Arrays.stream(exclusions))
.map(StringUtils::trim) .map(StringUtils::trim)
.toArray(String[]::new); .toArray(String[]::new);

+ 3
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/scanner/IssueExclusionsRegexpScanner.java Bestand weergeven

import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils; 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.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.LineRange;
import org.sonar.scanner.issue.ignore.pattern.PatternMatcher; import org.sonar.scanner.issue.ignore.pattern.PatternMatcher;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher; import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher;


public class IssueExclusionsRegexpScanner extends CharHandler { 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 StringBuilder sb = new StringBuilder();
private final List<Pattern> allFilePatterns; private final List<Pattern> allFilePatterns;

+ 2
- 24
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/AbstractModulePhaseExecutor.java Bestand weergeven

import java.util.Arrays; import java.util.Arrays;
import org.sonar.api.CoreProperties; import org.sonar.api.CoreProperties;
import org.sonar.api.batch.fs.InputFile; 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.AbstractProjectOrModule;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.InputModuleHierarchy; import org.sonar.api.batch.fs.internal.InputModuleHierarchy;
import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Loggers;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; 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.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.FileIndexer;


public abstract class AbstractModulePhaseExecutor { public abstract class AbstractModulePhaseExecutor {


private final PostJobsExecutor postJobsExecutor; private final PostJobsExecutor postJobsExecutor;
private final SensorsExecutor sensorsExecutor; private final SensorsExecutor sensorsExecutor;
private final DefaultModuleFileSystem fs; private final DefaultModuleFileSystem fs;
private final QProfileVerifier profileVerifier;
private final IssueExclusionsLoader issueExclusionsLoader; private final IssueExclusionsLoader issueExclusionsLoader;
private final InputModuleHierarchy hierarchy; private final InputModuleHierarchy hierarchy;
private final FileIndexer fileIndexer;
private final ModuleCoverageExclusions moduleCoverageExclusions; private final ModuleCoverageExclusions moduleCoverageExclusions;
private final ProjectCoverageExclusions projectCoverageExclusions; private final ProjectCoverageExclusions projectCoverageExclusions;
private final AnalysisWarnings analysisWarnings; private final AnalysisWarnings analysisWarnings;
private boolean warnCoverageAlreadyLogged; private boolean warnCoverageAlreadyLogged;


public AbstractModulePhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, InputModuleHierarchy hierarchy, DefaultModuleFileSystem fs, public AbstractModulePhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, InputModuleHierarchy hierarchy, DefaultModuleFileSystem fs,
QProfileVerifier profileVerifier, IssueExclusionsLoader issueExclusionsLoader, FileIndexer fileIndexer,
IssueExclusionsLoader issueExclusionsLoader,
ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions, ModuleCoverageExclusions moduleCoverageExclusions, ProjectCoverageExclusions projectCoverageExclusions,
AnalysisWarnings analysisWarnings) { AnalysisWarnings analysisWarnings) {
this.postJobsExecutor = postJobsExecutor; this.postJobsExecutor = postJobsExecutor;
this.sensorsExecutor = sensorsExecutor; this.sensorsExecutor = sensorsExecutor;
this.fs = fs; this.fs = fs;
this.profileVerifier = profileVerifier;
this.issueExclusionsLoader = issueExclusionsLoader; this.issueExclusionsLoader = issueExclusionsLoader;
this.hierarchy = hierarchy; this.hierarchy = hierarchy;
this.fileIndexer = fileIndexer;
this.moduleCoverageExclusions = moduleCoverageExclusions; this.moduleCoverageExclusions = moduleCoverageExclusions;
this.projectCoverageExclusions = projectCoverageExclusions; this.projectCoverageExclusions = projectCoverageExclusions;
this.analysisWarnings = analysisWarnings; this.analysisWarnings = analysisWarnings;
* Executed on each module * Executed on each module
*/ */
public final void execute(DefaultInputModule 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 // Initialize coverage exclusions
evaluateCoverageExclusions(module); evaluateCoverageExclusions(module);




protected abstract void executeOnRoot(); 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 Bestand weergeven

import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.notifications.AnalysisWarnings;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.issue.tracking.IssueTransition; 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.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scan.report.IssuesReports; import org.sonar.scanner.scan.report.IssuesReports;


public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor { public final class IssuesPhaseExecutor extends AbstractModulePhaseExecutor {
private final IssueTransition localIssueTracking; private final IssueTransition localIssueTracking;


public IssuesPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, 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); moduleCoverageExclusions, projectCoverageExclusions, analysisWarnings);
this.issuesReport = jsonReport; this.issuesReport = jsonReport;
this.localIssueTracking = localIssueTracking; this.localIssueTracking = localIssueTracking;

+ 5
- 7
sonar-scanner-engine/src/main/java/org/sonar/scanner/phases/PublishPhaseExecutor.java Bestand weergeven

import org.sonar.scanner.cpd.CpdExecutor; import org.sonar.scanner.cpd.CpdExecutor;
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;
import org.sonar.scanner.report.ReportPublisher; 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.DefaultModuleFileSystem;
import org.sonar.scanner.scan.filesystem.FileIndexer;
import org.sonar.scanner.scm.ScmPublisher; import org.sonar.scanner.scm.ScmPublisher;


public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor { public final class PublishPhaseExecutor extends AbstractModulePhaseExecutor {
private final ScmPublisher scm; private final ScmPublisher scm;


public PublishPhaseExecutor(PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor, 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); projectCoverageExclusions, analysisWarnings);
this.reportPublisher = reportPublisher; this.reportPublisher = reportPublisher;
this.cpdExecutor = cpdExecutor; this.cpdExecutor = cpdExecutor;

+ 9
- 11
sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/QProfileVerifier.java Bestand weergeven

import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.config.Configuration;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.scanner.scan.filesystem.InputComponentStore;


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


@ScannerSide
public class QProfileVerifier { public class QProfileVerifier {


private static final Logger LOG = LoggerFactory.getLogger(QProfileVerifier.class); 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; 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; this.profiles = profiles;
} }




@VisibleForTesting @VisibleForTesting
void execute(Logger logger) { 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); boolean defaultNameUsed = StringUtils.isBlank(defaultName);
for (String lang : fs.languages()) {
for (String lang : store.getLanguages()) {
QProfile profile = profiles.findByLanguage(lang); QProfile profile = profiles.findByLanguage(lang);
if (profile == null) { if (profile == null) {
logger.warn("No Quality profile found for language {}", lang); logger.warn("No Quality profile found for language {}", lang);
} }
} }
} }
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."); 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 Bestand weergeven

import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.internal.DefaultInputModule; 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.api.scan.filesystem.FileExclusions;
import org.sonar.core.extension.CoreExtensionsInstaller; import org.sonar.core.extension.CoreExtensionsInstaller;
import org.sonar.core.platform.ComponentContainer; import org.sonar.core.platform.ComponentContainer;
import org.sonar.scanner.deprecated.perspectives.ScannerPerspectives; import org.sonar.scanner.deprecated.perspectives.ScannerPerspectives;
import org.sonar.scanner.issue.ModuleIssueFilters; import org.sonar.scanner.issue.ModuleIssueFilters;
import org.sonar.scanner.issue.ModuleIssues; 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.AbstractModulePhaseExecutor;
import org.sonar.scanner.phases.IssuesPhaseExecutor; import org.sonar.scanner.phases.IssuesPhaseExecutor;
import org.sonar.scanner.phases.ModuleCoverageExclusions; import org.sonar.scanner.phases.ModuleCoverageExclusions;
import org.sonar.scanner.postjob.PostJobOptimizer; import org.sonar.scanner.postjob.PostJobOptimizer;
import org.sonar.scanner.rule.QProfileVerifier; import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.scan.filesystem.DefaultModuleFileSystem; 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.filesystem.ModuleInputComponentStore;
import org.sonar.scanner.scan.report.IssuesReports; import org.sonar.scanner.scan.report.IssuesReports;
import org.sonar.scanner.sensor.DefaultSensorContext; import org.sonar.scanner.sensor.DefaultSensorContext;
// file system // file system
ModuleInputComponentStore.class, ModuleInputComponentStore.class,
FileExclusions.class, FileExclusions.class,
ExclusionFilters.class,
MetadataGenerator.class,
FileMetadata.class,
FileIndexer.class,
InputFileBuilder.class,
DefaultModuleFileSystem.class, DefaultModuleFileSystem.class,
QProfileVerifier.class,


SensorOptimizer.class, SensorOptimizer.class,
PostJobOptimizer.class, PostJobOptimizer.class,
// issues // issues
ModuleIssues.class, ModuleIssues.class,


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

// Perspectives // Perspectives
ScannerPerspectives.class, ScannerPerspectives.class,



+ 32
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java Bestand weergeven

import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.sonar.api.batch.fs.internal.DefaultInputModule; 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.InputModuleHierarchy;
import org.sonar.api.batch.fs.internal.SensorStrategy; import org.sonar.api.batch.fs.internal.SensorStrategy;
import org.sonar.api.batch.rule.CheckFactory; import org.sonar.api.batch.rule.CheckFactory;
import org.sonar.scanner.deprecated.test.TestableBuilder; import org.sonar.scanner.deprecated.test.TestableBuilder;
import org.sonar.scanner.issue.DefaultProjectIssues; import org.sonar.scanner.issue.DefaultProjectIssues;
import org.sonar.scanner.issue.IssueCache; 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.DefaultServerLineHashesLoader;
import org.sonar.scanner.issue.tracking.IssueTransition; import org.sonar.scanner.issue.tracking.IssueTransition;
import org.sonar.scanner.issue.tracking.LocalIssueTracking; import org.sonar.scanner.issue.tracking.LocalIssueTracking;
import org.sonar.scanner.rule.ActiveRulesProvider; import org.sonar.scanner.rule.ActiveRulesProvider;
import org.sonar.scanner.rule.DefaultActiveRulesLoader; import org.sonar.scanner.rule.DefaultActiveRulesLoader;
import org.sonar.scanner.rule.DefaultRulesLoader; import org.sonar.scanner.rule.DefaultRulesLoader;
import org.sonar.scanner.rule.QProfileVerifier;
import org.sonar.scanner.rule.RulesLoader; import org.sonar.scanner.rule.RulesLoader;
import org.sonar.scanner.rule.RulesProvider; import org.sonar.scanner.rule.RulesProvider;
import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.branch.BranchType; import org.sonar.scanner.scan.branch.BranchType;
import org.sonar.scanner.scan.branch.ProjectBranchesProvider; import org.sonar.scanner.scan.branch.ProjectBranchesProvider;
import org.sonar.scanner.scan.branch.ProjectPullRequestsProvider; 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.InputComponentStore;
import org.sonar.scanner.scan.filesystem.LanguageDetection; 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.ScannerComponentIdGenerator;
import org.sonar.scanner.scan.filesystem.StatusDetection; import org.sonar.scanner.scan.filesystem.StatusDetection;
import org.sonar.scanner.scan.measure.DefaultMetricFinder; import org.sonar.scanner.scan.measure.DefaultMetricFinder;
new ScmChangedFilesProvider(), new ScmChangedFilesProvider(),
StatusDetection.class, StatusDetection.class,
LanguageDetection.class, LanguageDetection.class,
MetadataGenerator.class,
FileMetadata.class,
FileIndexer.class,
ProjectFileIndexer.class,
ProjectExclusionFilters.class,



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


// issues // issues
IssueCache.class, IssueCache.class,
// Measures // Measures
MeasureCache.class, MeasureCache.class,


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

// context // context
ContextPropertiesCache.class, ContextPropertiesCache.class,
ContextPropertiesPublisher.class, ContextPropertiesPublisher.class,
LOG.info("Branch name: {}, type: {}", branchConfig.branchName(), branchTypeToDisplayName(branchConfig.branchType())); 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"); LOG.debug("Start recursive analysis of project modules");
scanRecursively(tree, tree.root(), analysisMode); scanRecursively(tree, tree.root(), analysisMode);



+ 171
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/AbstractExclusionFilters.java Bestand weergeven

/*
* 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 Bestand weergeven

/*
* 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 Bestand weergeven

*/ */
package org.sonar.scanner.scan.filesystem; package org.sonar.scanner.scan.filesystem;


import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.io.IOException; 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.LinkOption;
import java.nio.file.Path; 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 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;
import org.sonar.api.batch.fs.InputFile.Type; import org.sonar.api.batch.fs.InputFile.Type;
import org.sonar.api.batch.fs.InputFileFilter; 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.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule; 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.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; import org.sonar.scanner.util.ProgressReport;


/** /**
* Index input files into {@link InputComponentStore}. * Index input files into {@link InputComponentStore}.
*/ */
@ScannerSide
public class FileIndexer { 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 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 ScannerComponentIdGenerator scannerComponentIdGenerator;
private final InputComponentStore componentStore; 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 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.scannerComponentIdGenerator = scannerComponentIdGenerator;
this.componentStore = componentStore; 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.langDetection = languageDetection;
this.analysisWarnings = analysisWarnings;
this.properties = properties;
this.filters = filters; 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 // get case of real file without resolving link
Path realAbsoluteFile = sourceFile.toRealPath(LinkOption.NOFOLLOW_LINKS).toAbsolutePath().normalize(); 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) { if (language == null && langDetection.getForcedLanguage() != null) {
LOG.warn("File '{}' is ignored because it doesn't belong to the forced language '{}'", realAbsoluteFile.toAbsolutePath(), langDetection.getForcedLanguage()); 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)) { 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) { private boolean accept(InputFile indexedFile) {
return true; 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 Bestand weergeven

import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileExtensionPredicate; import org.sonar.api.batch.fs.internal.FileExtensionPredicate;
import org.sonar.api.scanner.fs.InputProject;
import org.sonar.scanner.scan.branch.BranchConfiguration; import org.sonar.scanner.scan.branch.BranchConfiguration;


/** /**
private final Map<String, InputComponent> inputComponents = new HashMap<>(); private final Map<String, InputComponent> inputComponents = new HashMap<>();
private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create(); private final SetMultimap<String, InputFile> filesByNameCache = LinkedHashMultimap.create();
private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create(); private final SetMultimap<String, InputFile> filesByExtensionCache = LinkedHashMultimap.create();
private final InputProject project;
private final BranchConfiguration branchConfiguration; private final BranchConfiguration branchConfiguration;


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


::iterator; ::iterator;
} }


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



+ 0
- 71
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputFileBuilder.java Bestand weergeven

/*
* 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 Bestand weergeven

import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset; 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.InputFile.Type;
import org.sonar.api.batch.fs.internal.DefaultInputFile; 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.FileMetadata;
import org.sonar.api.batch.fs.internal.Metadata; 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; import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader;


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




private final StatusDetection statusDetection; private final StatusDetection statusDetection;
private final FileMetadata fileMetadata; private final FileMetadata fileMetadata;
private final DefaultInputModule inputModule;
private final IssueExclusionsLoader exclusionsScanner; 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.statusDetection = statusDetection;
this.fileMetadata = fileMetadata; this.fileMetadata = fileMetadata;
this.exclusionsScanner = exclusionsScanner; this.exclusionsScanner = exclusionsScanner;
* Sets all metadata in the file, including charset and status. * Sets all metadata in the file, including charset and status.
* It is an expensive computation, reading the entire file. * 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); CharsetDetector charsetDetector = new CharsetDetector(inputFile.path(), defaultEncoding);
try { try {
Charset charset; Charset charset;
inputFile.setCharset(charset); inputFile.setCharset(charset);
Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile.key())); Metadata metadata = fileMetadata.readMetadata(is, charset, inputFile.absolutePath(), exclusionsScanner.createCharHandlerFor(inputFile.key()));
inputFile.setMetadata(metadata); 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) { } catch (Exception e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }

+ 35
- 0
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ModuleExclusionFilters.java Bestand weergeven

/*
* 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 Bestand weergeven

/*
* 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 Bestand weergeven

/*
* 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 Bestand weergeven

when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir)); when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir));


DefaultInputProject project = TestInputFileBuilder.newDefaultInputProject("foo", baseDir); 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); executor = new CpdExecutor(settings, index, publisher, componentStore, executorService);
reader = new ScannerReportReader(outputDir); reader = new ScannerReportReader(outputDir);



+ 124
- 32
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/fs/FileSystemMediumTest.java Bestand weergeven

import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.utils.MessageException; import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2; 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.AnalysisResult;
import org.sonar.scanner.mediumtest.LogOutputRecorder;
import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.xoo.XooPlugin; import org.sonar.xoo.XooPlugin;
import org.sonar.xoo.global.GlobalSensor; import org.sonar.xoo.global.GlobalSensor;
import org.sonar.xoo.rule.XooRulesDefinition; import org.sonar.xoo.rule.XooRulesDefinition;


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


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


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


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


private File baseDir; private File baseDir;
private ImmutableMap.Builder<String, String> builder; private ImmutableMap.Builder<String, String> builder;
.build()) .build())
.execute(); .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 @Test
.build()) .build())
.execute(); .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 @Test
.build()) .build())
.execute(); .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 @Test
File javaFile = new File(srcDir, "sample.java"); File javaFile = new File(srcDir, "sample.java");
FileUtils.write(javaFile, "Sample xoo\ncontent"); FileUtils.write(javaFile, "Sample xoo\ncontent");


logTester.setLevel(LoggerLevel.DEBUG);

tester.newAnalysis() tester.newAnalysis()
.properties(builder .properties(builder
.put("sonar.sources", "src") .put("sonar.sources", "src")
.build()) .build())
.execute(); .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");


} }


File javaFile = new File(srcDir, "sample.java"); File javaFile = new File(srcDir, "sample.java");
FileUtils.write(javaFile, "Sample xoo\ncontent"); FileUtils.write(javaFile, "Sample xoo\ncontent");


logTester.setLevel(LoggerLevel.DEBUG);

tester.newAnalysis() tester.newAnalysis()
.properties(builder .properties(builder
.put("sonar.sources", "src") .put("sonar.sources", "src")
.build()) .build())
.execute(); .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 @Test
Path javaFile = mainDir.resolve("sample.java"); Path javaFile = mainDir.resolve("sample.java");
Files.write(javaFile, "Sample xoo\ncontent".getBytes(StandardCharsets.UTF_8)); Files.write(javaFile, "Sample xoo\ncontent".getBytes(StandardCharsets.UTF_8));


logTester.setLevel(LoggerLevel.DEBUG);

AnalysisResult result = tester.newAnalysis() AnalysisResult result = tester.newAnalysis()
.properties(builder .properties(builder
.put("sonar.sources", "src/main") .put("sonar.sources", "src/main")
.build()) .build())
.execute(); .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"); DefaultInputFile javaInputFile = (DefaultInputFile) result.inputFile("src/main/sample.java");


thrown.expect(IllegalStateException.class); thrown.expect(IllegalStateException.class);
File xooFile = new File(srcDir, "sample.unknown"); File xooFile = new File(srcDir, "sample.unknown");
FileUtils.write(xooFile, "Sample xoo\ncontent"); FileUtils.write(xooFile, "Sample xoo\ncontent");


logTester.setLevel(LoggerLevel.DEBUG);

AnalysisResult result = tester.newAnalysis() AnalysisResult result = tester.newAnalysis()
.properties(builder .properties(builder
.put("sonar.sources", "src") .put("sonar.sources", "src")
.build()) .build())
.execute(); .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"); DefaultInputFile inputFile = (DefaultInputFile) result.inputFile("src/sample.unknown");
assertThat(result.getReportComponent(inputFile)).isNotNull(); assertThat(result.getReportComponent(inputFile)).isNotNull();
} }
new Random().nextBytes(b); new Random().nextBytes(b);
FileUtils.writeByteArrayToFile(unknownFile, b); FileUtils.writeByteArrayToFile(unknownFile, b);


logTester.setLevel(LoggerLevel.DEBUG);

tester.newAnalysis() tester.newAnalysis()
.properties(builder .properties(builder
.put("sonar.sources", "src") .put("sonar.sources", "src")
.build()) .build())
.execute(); .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 @Test
File unknownFile = new File(srcDir, "myfile.binary"); File unknownFile = new File(srcDir, "myfile.binary");
FileUtils.write(unknownFile, "some text"); FileUtils.write(unknownFile, "some text");


logTester.setLevel(LoggerLevel.DEBUG);

tester.newAnalysis() tester.newAnalysis()
.properties(builder .properties(builder
.put("sonar.sources", "src") .put("sonar.sources", "src")
.build()) .build())
.execute(); .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 @Test
assertThat(result.inputFiles()).hasSize(2); 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 @Test
public void failForDuplicateInputFile() throws IOException { public void failForDuplicateInputFile() throws IOException {
File srcDir = new File(baseDir, "src"); File srcDir = new File(baseDir, "src");
.execute(); .execute();


assertThat(result.inputFiles()).hasSize(4); 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_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_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", "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 Bestand weergeven

import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.AnalysisMode; 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.fs.internal.TestInputFileBuilder;
import org.sonar.api.batch.postjob.issue.PostJobIssue; import org.sonar.api.batch.postjob.issue.PostJobIssue;
import org.sonar.api.batch.rule.Severity; import org.sonar.api.batch.rule.Severity;
@Before @Before
public void setUp() throws IOException { public void setUp() throws IOException {
issueCache = mock(IssueCache.class); 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(); settings = new MapSettings();
analysisMode = mock(AnalysisMode.class); analysisMode = mock(AnalysisMode.class);
context = new DefaultPostJobContext(settings.asConfig(), settings, issueCache, componentStore, analysisMode); context = new DefaultPostJobContext(settings.asConfig(), settings, issueCache, componentStore, analysisMode);

+ 5
- 5
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java Bestand weergeven

.setWorkDir(temp.newFolder()); .setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1); DefaultInputProject project = new DefaultInputProject(rootDef, 1);


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


Path moduleBaseDir = temp.newFolder().toPath(); Path moduleBaseDir = temp.newFolder().toPath();
ProjectDefinition module1Def = ProjectDefinition.create() ProjectDefinition module1Def = ProjectDefinition.create()


DefaultInputProject project = new DefaultInputProject(rootDef, 1); DefaultInputProject project = new DefaultInputProject(rootDef, 1);


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


ComponentsPublisher publisher = new ComponentsPublisher(project, store); ComponentsPublisher publisher = new ComponentsPublisher(project, store);
publisher.publish(writer); publisher.publish(writer);
.setWorkDir(temp.newFolder()); .setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1); 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) DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.java", 5)
.setLines(2) .setLines(2)
.setWorkDir(temp.newFolder()); .setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1); DefaultInputProject project = new DefaultInputProject(rootDef, 1);


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


.setWorkDir(temp.newFolder()); .setWorkDir(temp.newFolder());
DefaultInputProject project = new DefaultInputProject(rootDef, 1); DefaultInputProject project = new DefaultInputProject(rootDef, 1);


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



+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java Bestand weergeven

String moduleKey = "foo"; String moduleKey = "foo";
inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setLines(5).build(); inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setLines(5).build();
DefaultInputProject rootModule = TestInputFileBuilder.newDefaultInputProject(moduleKey, temp.newFolder()); 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); componentCache.put(moduleKey, inputFile);


measureCache = mock(MeasureCache.class); measureCache = mock(MeasureCache.class);

+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java Bestand weergeven

String projectKey = "foo"; String projectKey = "foo";
project = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder()); project = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder());
inputFile = new TestInputFileBuilder(projectKey, "src/Foo.php").setPublish(true).build(); 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); componentCache.put(projectKey, inputFile);
measureCache = mock(MeasureCache.class); measureCache = mock(MeasureCache.class);
when(measureCache.byComponentKey(anyString())).thenReturn(Collections.<DefaultMeasure<?>>emptyList()); when(measureCache.byComponentKey(anyString())).thenReturn(Collections.<DefaultMeasure<?>>emptyList());

+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java Bestand weergeven

.build(); .build();


DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(moduleKey, baseDir); 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); componentStore.put(moduleKey, inputFile);


publisher = new SourcePublisher(componentStore); publisher = new SourcePublisher(componentStore);

+ 12
- 11
sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java Bestand weergeven

import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.config.internal.MapSettings; import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.MessageException; 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.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@Rule @Rule
public ExpectedException thrown = ExpectedException.none(); public ExpectedException thrown = ExpectedException.none();


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


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


@Test @Test
public void should_log_all_used_profiles() { 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); Logger logger = mock(Logger.class);
profileLogger.execute(logger); profileLogger.execute(logger);




@Test @Test
public void should_fail_if_default_profile_not_used() { 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"); 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.expect(MessageException.class);
thrown.expectMessage("sonar.profile was set to 'Unknown' but didn't match any profile for any language. Please check your configuration."); thrown.expectMessage("sonar.profile was set to 'Unknown' but didn't match any profile for any language. Please check your configuration.");
public void should_not_fail_if_no_language_on_project() { public void should_not_fail_if_no_language_on_project() {
settings.setProperty("sonar.profile", "Unknown"); settings.setProperty("sonar.profile", "Unknown");


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


profileLogger.execute(); profileLogger.execute();




@Test @Test
public void should_not_fail_if_default_profile_used_at_least_once() { 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"); 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(); profileLogger.execute();
} }

+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java Bestand weergeven

private InputComponentStore componentStore; private InputComponentStore componentStore;


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

+ 2
- 2
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java Bestand weergeven

DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(rootDef); DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(rootDef);
DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(moduleDef); DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(moduleDef);


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


DefaultInputFile fooFile = new TestInputFileBuilder(rootModuleKey, "src/main/java/Foo.java") DefaultInputFile fooFile = new TestInputFileBuilder(rootModuleKey, "src/main/java/Foo.java")


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


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

+ 0
- 91
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputFileBuilderTest.java Bestand weergeven

/*
* 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 Bestand weergeven

import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile; 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.FileMetadata;
import org.sonar.api.batch.fs.internal.TestInputFileBuilder; import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
import org.sonar.api.utils.PathUtils; import org.sonar.api.utils.PathUtils;
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
metadata = new FileMetadata(); metadata = new FileMetadata();
IssueExclusionsLoader issueExclusionsLoader = new IssueExclusionsLoader(mock(IssueExclusionPatternInitializer.class), mock(PatternMatcher.class)); 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 @Test
DefaultInputFile inputFile = new TestInputFileBuilder("struts", relativePath) DefaultInputFile inputFile = new TestInputFileBuilder("struts", relativePath)
.setModuleBaseDir(baseDir) .setModuleBaseDir(baseDir)
.build(); .build();
generator.setMetadata(inputFile, StandardCharsets.US_ASCII);
generator.setMetadata("module", inputFile, StandardCharsets.US_ASCII);
return inputFile; return inputFile;
} }



+ 1
- 1
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java Bestand weergeven

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


@Test @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 Bestand weergeven

import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultIndexedFile; import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
import org.sonar.api.config.internal.MapSettings; import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.scan.filesystem.FileExclusions;


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


public class ExclusionFiltersTest {
public class ProjectExclusionFiltersTest {


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


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


@Test @Test
public void no_inclusions_nor_exclusions() throws IOException { 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); 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(); assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
@Test @Test
public void match_inclusion() throws IOException { public void match_inclusion() throws IOException {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java"); 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); 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(); assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();
@Test @Test
public void match_at_least_one_inclusion() throws IOException { public void match_at_least_one_inclusion() throws IOException {
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "**/*Dao.java,**/*Dto.java"); 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); 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(); assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();
settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*"); settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
settings.setProperty(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, "src/test/java/**/*"); settings.setProperty(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY, "src/test/java/**/*");
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "**/*Dao.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); 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(); assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isFalse();


settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*"); settings.setProperty(CoreProperties.PROJECT_INCLUSIONS_PROPERTY, "src/main/java/**/*");
settings.setProperty(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY, "file:" + excludedFile.getAbsolutePath()); 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); 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(); assertThat(filter.accept(indexedFile.path(), Paths.get(indexedFile.relativePath()), InputFile.Type.MAIN)).isTrue();


@Test @Test
public void trim_pattern() { 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 Bestand weergeven



ProjectDefinition def = ProjectDefinition.create().setBaseDir(projectBaseDir).setWorkDir(temp.newFolder()).setKey("struts"); ProjectDefinition def = ProjectDefinition.create().setBaseDir(projectBaseDir).setWorkDir(temp.newFolder()).setKey("struts");
DefaultInputProject project = new DefaultInputProject(def, 1); 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") DefaultInputFile inputFile = new TestInputFileBuilder("struts", "src/main/java/org/apache/struts/Action.java")
.setModuleBaseDir(projectBaseDir.toPath()).build(); .setModuleBaseDir(projectBaseDir.toPath()).build();

Laden…
Annuleren
Opslaan