]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13867 Collect number of indexed C/C++ files in the scanner
authorMichal Duda <michal.duda@sonarsource.com>
Fri, 11 Sep 2020 12:30:31 +0000 (14:30 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 17 Sep 2020 20:07:12 +0000 (20:07 +0000)
14 files changed:
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MetadataPublisher.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/FileIndexer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/InputComponentStore.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/filesystem/ProjectFileIndexer.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/cpd/CpdExecutorTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/ComponentsPublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MetadataPublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/SourcePublisherTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/QProfileVerifierTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/ModuleIndexerTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/InputComponentStoreTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/filesystem/ModuleInputComponentStoreTest.java
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java
sonar-scanner-protocol/src/main/protobuf/scanner_report.proto

index 3eb0ed895176ab733f9aac359b1a65c4428cace2..67e6ea792699860818dd96f55a900f981a438590 100644 (file)
@@ -25,7 +25,6 @@ import java.time.Instant;
 import java.util.LinkedList;
 import java.util.Map.Entry;
 import java.util.regex.Pattern;
-import javax.annotation.Nullable;
 import org.sonar.api.batch.fs.internal.AbstractProjectOrModule;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.api.batch.scm.ScmProvider;
@@ -44,6 +43,7 @@ import org.sonar.scanner.rule.QProfile;
 import org.sonar.scanner.rule.QualityProfiles;
 import org.sonar.scanner.scan.ScanProperties;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
 import org.sonar.scanner.scm.ScmConfiguration;
 import org.sonar.scanner.scm.ScmRevision;
 
@@ -60,12 +60,12 @@ public class MetadataPublisher implements ReportPublisherStep {
   private final BranchConfiguration branchConfiguration;
   private final ScmRevision scmRevision;
   private final ForkDateSupplier forkDateSupplier;
-  @Nullable
+  private final InputComponentStore componentStore;
   private final ScmConfiguration scmConfiguration;
 
   public MetadataPublisher(ProjectInfo projectInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties,
     QualityProfiles qProfiles, CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration,
-    ScmRevision scmRevision, ForkDateSupplier forkDateSupplier, @Nullable ScmConfiguration scmConfiguration) {
+    ScmRevision scmRevision, ForkDateSupplier forkDateSupplier, InputComponentStore componentStore, ScmConfiguration scmConfiguration) {
     this.projectInfo = projectInfo;
     this.moduleHierarchy = moduleHierarchy;
     this.properties = properties;
@@ -75,14 +75,10 @@ public class MetadataPublisher implements ReportPublisherStep {
     this.branchConfiguration = branchConfiguration;
     this.scmRevision = scmRevision;
     this.forkDateSupplier = forkDateSupplier;
+    this.componentStore = componentStore;
     this.scmConfiguration = scmConfiguration;
   }
 
-  public MetadataPublisher(ProjectInfo projectInfo, InputModuleHierarchy moduleHierarchy, ScanProperties properties, QualityProfiles qProfiles,
-    CpdSettings cpdSettings, ScannerPluginRepository pluginRepository, BranchConfiguration branchConfiguration, ScmRevision scmRevision, ForkDateSupplier forkDateSupplier) {
-    this(projectInfo, moduleHierarchy, properties, qProfiles, cpdSettings, pluginRepository, branchConfiguration, scmRevision, forkDateSupplier, null);
-  }
-
   @Override
   public void publish(ScannerReportWriter writer) {
     AbstractProjectOrModule rootProject = moduleHierarchy.root();
@@ -103,6 +99,7 @@ public class MetadataPublisher implements ReportPublisherStep {
 
     addScmInformation(builder);
     addForkPoint(builder);
+    addNotAnalyzedFileCountsByLanguage(builder);
 
     for (QProfile qp : qProfiles.findAll()) {
       builder.putQprofilesPerLanguage(qp.getLanguage(), ScannerReport.Metadata.QProfile.newBuilder()
@@ -142,16 +139,16 @@ public class MetadataPublisher implements ReportPublisherStep {
       }
     }
 
-    if (scmConfiguration != null) {
-      ScmProvider scmProvider = scmConfiguration.provider();
-      if (scmProvider != null) {
-        Path projectBasedir = moduleHierarchy.root().getBaseDir();
-        try {
-          builder.setRelativePathFromScmRoot(toSonarQubePath(scmProvider.relativePathFromScmRoot(projectBasedir)));
-        } catch (UnsupportedOperationException e) {
-          LOG.debug(e.getMessage());
-        }
-      }
+    ScmProvider scmProvider = scmConfiguration.provider();
+    if (scmProvider == null) {
+      return;
+    }
+
+    Path projectBasedir = moduleHierarchy.root().getBaseDir();
+    try {
+      builder.setRelativePathFromScmRoot(toSonarQubePath(scmProvider.relativePathFromScmRoot(projectBasedir)));
+    } catch (UnsupportedOperationException e) {
+      LOG.debug(e.getMessage());
     }
   }
 
@@ -166,6 +163,10 @@ public class MetadataPublisher implements ReportPublisherStep {
     }
   }
 
+  private void addNotAnalyzedFileCountsByLanguage(ScannerReport.Metadata.Builder builder) {
+    builder.putAllNotAnalyzedFilesByLanguage(componentStore.getNotAnalysedFilesByLanguage());
+  }
+
   private void addBranchInformation(ScannerReport.Metadata.Builder builder) {
     builder.setBranchName(branchConfiguration.branchName());
     BranchType branchType = toProtobufBranchType(branchConfiguration.branchType());
index 21435f623ad3b3e9e398a9101cad172ef857f93a..ed533e97999dd4afacbfb493a3ceca99b216a9c8 100644 (file)
@@ -30,16 +30,16 @@ import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputFile.Type;
 import org.sonar.api.batch.fs.InputFileFilter;
+import org.sonar.api.batch.fs.internal.DefaultIndexedFile;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.DefaultInputModule;
+import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.batch.fs.internal.SensorStrategy;
 import org.sonar.api.batch.scm.IgnoreCommand;
 import org.sonar.api.notifications.AnalysisWarnings;
 import org.sonar.api.utils.MessageException;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.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.scanner.issue.ignore.scanner.IssueExclusionsLoader;
 import org.sonar.scanner.scan.ScanProperties;
 import org.sonar.scanner.util.ProgressReport;
@@ -52,6 +52,7 @@ import static java.lang.String.format;
 public class FileIndexer {
 
   private static final Logger LOG = Loggers.get(FileIndexer.class);
+
   private final AnalysisWarnings analysisWarnings;
   private final ScanProperties properties;
   private final InputFileFilter[] filters;
@@ -89,10 +90,11 @@ public class FileIndexer {
   }
 
   public FileIndexer(DefaultInputProject project, ScannerComponentIdGenerator scannerComponentIdGenerator, InputComponentStore componentStore,
-    ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions, IssueExclusionsLoader issueExclusionsLoader,
-    MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy, LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
-    this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader, metadataGenerator,
-      sensorStrategy, languageDetection, analysisWarnings, properties, new InputFileFilter[0]);
+    ProjectExclusionFilters projectExclusionFilters, ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions,
+    IssueExclusionsLoader issueExclusionsLoader, MetadataGenerator metadataGenerator, SensorStrategy sensorStrategy,
+    LanguageDetection languageDetection, AnalysisWarnings analysisWarnings, ScanProperties properties) {
+    this(project, scannerComponentIdGenerator, componentStore, projectExclusionFilters, projectCoverageAndDuplicationExclusions, issueExclusionsLoader,
+      metadataGenerator, sensorStrategy, languageDetection, analysisWarnings, properties, new InputFileFilter[0]);
   }
 
   void indexFile(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions,
@@ -269,5 +271,4 @@ public class FileIndexer {
   private static String pluralizeFiles(int count) {
     return count == 1 ? "file" : "files";
   }
-
 }
index 627da73d5fe876c630c18caee982b1f5cff8144a..1f757db9bbee3dbe5315d94954c518e689006fd2 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.scanner.scan.filesystem;
 
+import com.google.common.collect.ImmutableMap;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -29,8 +30,11 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.regex.Pattern;
 import java.util.stream.Stream;
 import javax.annotation.CheckForNull;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.fs.InputComponent;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.internal.DefaultFileSystem;
@@ -47,6 +51,9 @@ import static org.sonar.api.utils.Preconditions.checkState;
  * exclusion patterns are already applied.
  */
 public class InputComponentStore extends DefaultFileSystem.Cache {
+  private static final Map<String, Pattern> FILE_PATTERN_BY_LANGUAGE = ImmutableMap.of(
+    "C", Pattern.compile(".*\\.c", Pattern.CASE_INSENSITIVE),
+    "C++", Pattern.compile(".*\\.cpp|.*\\.cc|.*\\.cxx|.*\\.c\\+\\+", Pattern.CASE_INSENSITIVE));
 
   private final SortedSet<String> globalLanguagesCache = new TreeSet<>();
   private final Map<String, SortedSet<String>> languagesCache = new HashMap<>();
@@ -58,9 +65,12 @@ public class InputComponentStore extends DefaultFileSystem.Cache {
   private final Map<String, Set<InputFile>> filesByNameCache = new HashMap<>();
   private final Map<String, Set<InputFile>> filesByExtensionCache = new HashMap<>();
   private final BranchConfiguration branchConfiguration;
+  private final SonarRuntime sonarRuntime;
+  private final Map<String, Integer> notAnalysedFilesByLanguage = new HashMap<>();
 
-  public InputComponentStore(BranchConfiguration branchConfiguration) {
+  public InputComponentStore(BranchConfiguration branchConfiguration, SonarRuntime sonarRuntime) {
     this.branchConfiguration = branchConfiguration;
+    this.sonarRuntime = sonarRuntime;
   }
 
   public Collection<InputComponent> all() {
@@ -97,6 +107,8 @@ public class InputComponentStore extends DefaultFileSystem.Cache {
 
   public InputComponentStore put(String moduleKey, InputFile inputFile) {
     DefaultInputFile file = (DefaultInputFile) inputFile;
+    updateNotAnalysedCAndCppFileCount(file);
+
     addToLanguageCache(moduleKey, file);
     inputFileByModuleCache.computeIfAbsent(moduleKey, x -> new HashMap<>()).put(file.getModuleRelativePath(), inputFile);
     inputModuleKeyByFileCache.put(inputFile, moduleKey);
@@ -169,4 +181,19 @@ public class InputComponentStore extends DefaultFileSystem.Cache {
     throw new UnsupportedOperationException();
   }
 
+  private void updateNotAnalysedCAndCppFileCount(DefaultInputFile inputFile) {
+    if (!SonarEdition.COMMUNITY.equals(sonarRuntime.getEdition())) {
+      return;
+    }
+
+    FILE_PATTERN_BY_LANGUAGE.forEach((language, filePattern) -> {
+      if (filePattern.matcher(inputFile.filename()).matches()) {
+        notAnalysedFilesByLanguage.put(language, notAnalysedFilesByLanguage.getOrDefault(language, 0) + 1);
+      }
+    });
+  }
+
+  public Map<String, Integer> getNotAnalysedFilesByLanguage() {
+    return ImmutableMap.copyOf(notAnalysedFilesByLanguage);
+  }
 }
index 5f4da8fae26b38a8b87e6fb416695bfbda4f2ce6..e33909d47fb1b5a9a485b65d6bf9064135771211 100644 (file)
@@ -64,7 +64,7 @@ public class ProjectFileIndexer {
   private static final Logger LOG = Loggers.get(ProjectFileIndexer.class);
   private final ProjectExclusionFilters projectExclusionFilters;
   private final ProjectCoverageAndDuplicationExclusions projectCoverageAndDuplicationExclusions;
-  private ScmConfiguration scmConfiguration;
+  private final ScmConfiguration scmConfiguration;
   private final InputComponentStore componentStore;
   private final InputModuleHierarchy inputModuleHierarchy;
   private final GlobalConfiguration globalConfig;
@@ -189,14 +189,15 @@ public class ProjectFileIndexer {
     return count == 1 ? "file" : "files";
   }
 
-  private void indexFiles(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters, ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions,
-    List<Path> sources, Type type, ExclusionCounter exclusionCounter) {
+  private void indexFiles(DefaultInputModule module, ModuleExclusionFilters moduleExclusionFilters,
+    ModuleCoverageAndDuplicationExclusions moduleCoverageAndDuplicationExclusions, List<Path> sources, Type type, ExclusionCounter exclusionCounter) {
     try {
       for (Path dirOrFile : sources) {
         if (dirOrFile.toFile().isDirectory()) {
           indexDirectory(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, dirOrFile, type, exclusionCounter);
         } else {
-          fileIndexer.indexFile(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, dirOrFile, type, progressReport, exclusionCounter, ignoreCommand);
+          fileIndexer.indexFile(module, moduleExclusionFilters, moduleCoverageAndDuplicationExclusions, dirOrFile, type, progressReport, exclusionCounter,
+            ignoreCommand);
         }
       }
     } catch (IOException e) {
index 7598a64e485454a87fcfda69db2424c06bb6e004..f8614ce4fcc1d219e7cc025c4a8dc10464ab1f84 100644 (file)
@@ -36,6 +36,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 import org.mockito.ArgumentMatchers;
+import org.sonar.api.SonarRuntime;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.api.utils.log.LoggerLevel;
 import org.sonar.core.util.CloseableIterator;
@@ -72,10 +73,11 @@ public class CpdExecutorTest {
   public ExpectedException thrown = ExpectedException.none();
 
   private CpdExecutor executor;
-  private ExecutorService executorService = mock(ExecutorService.class);
-  private CpdSettings settings = mock(CpdSettings.class);
-  private ReportPublisher publisher = mock(ReportPublisher.class);
-  private SonarCpdBlockIndex index = new SonarCpdBlockIndex(publisher, settings);
+  private final ExecutorService executorService = mock(ExecutorService.class);
+  private final CpdSettings settings = mock(CpdSettings.class);
+  private final ReportPublisher publisher = mock(ReportPublisher.class);
+  private final SonarRuntime sonarRuntime = mock(SonarRuntime.class);
+  private final SonarCpdBlockIndex index = new SonarCpdBlockIndex(publisher, settings);
   private ScannerReportReader reader;
   private DefaultInputFile batchComponent1;
   private DefaultInputFile batchComponent2;
@@ -90,7 +92,7 @@ public class CpdExecutorTest {
     when(publisher.getWriter()).thenReturn(new ScannerReportWriter(outputDir));
 
     DefaultInputProject project = TestInputFileBuilder.newDefaultInputProject("foo", baseDir);
-    componentStore = new InputComponentStore(mock(BranchConfiguration.class));
+    componentStore = new InputComponentStore(mock(BranchConfiguration.class), sonarRuntime);
     executor = new CpdExecutor(settings, index, publisher, componentStore, executorService);
     reader = new ScannerReportReader(outputDir);
 
index c1458524e5127781cea6bd77b107edb4ba2e7a3c..74bc606295f83238442f1a8526c4c8dfac0392f3 100644 (file)
@@ -27,6 +27,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.sonar.api.CoreProperties;
+import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputFile.Type;
@@ -49,6 +50,9 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 public class ComponentsPublisherTest {
+
+  private final SonarRuntime sonarRuntime = mock(SonarRuntime.class);
+
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
@@ -77,7 +81,7 @@ public class ComponentsPublisherTest {
       .setWorkDir(temp.newFolder());
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration, sonarRuntime);
 
     Path moduleBaseDir = temp.newFolder().toPath();
     ProjectDefinition module1Def = ProjectDefinition.create()
@@ -143,7 +147,7 @@ public class ComponentsPublisherTest {
       .setWorkDir(temp.newFolder());
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration, sonarRuntime);
 
     DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.java", 5)
       .setLines(2)
@@ -180,7 +184,7 @@ public class ComponentsPublisherTest {
       .setWorkDir(temp.newFolder());
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration, sonarRuntime);
     ComponentsPublisher publisher = new ComponentsPublisher(project, store);
     publisher.publish(writer);
 
@@ -210,7 +214,7 @@ public class ComponentsPublisherTest {
       .setWorkDir(temp.newFolder());
     DefaultInputProject project = new DefaultInputProject(rootDef, 1);
 
-    InputComponentStore store = new InputComponentStore(branchConfiguration);
+    InputComponentStore store = new InputComponentStore(branchConfiguration, sonarRuntime);
     ComponentsPublisher publisher = new ComponentsPublisher(project, store);
     publisher.publish(writer);
 
index 53d37e99363785d16585742fd4ec7fcf05586e6e..f6f176d8cff8a410c61e7a5675eaebe34650ecf4 100644 (file)
@@ -56,6 +56,7 @@ import org.sonar.scanner.rule.QualityProfiles;
 import org.sonar.scanner.scan.ScanProperties;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.branch.BranchType;
+import org.sonar.scanner.scan.filesystem.InputComponentStore;
 import org.sonar.scanner.scm.ScmConfiguration;
 import org.sonar.scanner.scm.ScmRevision;
 
@@ -73,19 +74,18 @@ public class MetadataPublisherTest {
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
-  private DefaultInputModule rootModule;
   private MetadataPublisher underTest;
-  private ScanProperties properties = mock(ScanProperties.class);
-  private QualityProfiles qProfiles = mock(QualityProfiles.class);
-  private ProjectInfo projectInfo = mock(ProjectInfo.class);
-  private CpdSettings cpdSettings = mock(CpdSettings.class);
-  private InputModuleHierarchy inputModuleHierarchy;
-  private ForkDateSupplier forkDateSupplier = mock(ForkDateSupplier.class);
-  private ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
+  private final ScanProperties properties = mock(ScanProperties.class);
+  private final QualityProfiles qProfiles = mock(QualityProfiles.class);
+  private final ProjectInfo projectInfo = mock(ProjectInfo.class);
+  private final CpdSettings cpdSettings = mock(CpdSettings.class);
+  private final ForkDateSupplier forkDateSupplier = mock(ForkDateSupplier.class);
+  private final ScannerPluginRepository pluginRepository = mock(ScannerPluginRepository.class);
   private BranchConfiguration branches;
   private ScmConfiguration scmConfiguration;
-  private ScmProvider scmProvider = mock(ScmProvider.class);
-  private ScmRevision scmRevision = mock(ScmRevision.class);
+  private final ScmProvider scmProvider = mock(ScmProvider.class);
+  private final ScmRevision scmRevision = mock(ScmRevision.class);
+  private final InputComponentStore componentStore = mock(InputComponentStore.class);
 
   @Before
   public void prepare() throws IOException {
@@ -101,11 +101,11 @@ public class MetadataPublisherTest {
     Path rootBaseDir = temp.newFolder().toPath();
     Path moduleBaseDir = rootBaseDir.resolve("moduleDir");
     Files.createDirectory(moduleBaseDir);
-    rootModule = new DefaultInputModule(def
+    DefaultInputModule rootModule = new DefaultInputModule(def
       .setBaseDir(rootBaseDir.toFile())
       .setKey("root")
       .setWorkDir(temp.newFolder()), TestInputFileBuilder.nextBatchId());
-    inputModuleHierarchy = mock(InputModuleHierarchy.class);
+    InputModuleHierarchy inputModuleHierarchy = mock(InputModuleHierarchy.class);
     when(inputModuleHierarchy.root()).thenReturn(rootModule);
     DefaultInputModule child = new DefaultInputModule(ProjectDefinition.create()
       .setKey("module")
@@ -118,7 +118,7 @@ public class MetadataPublisherTest {
     scmConfiguration = mock(ScmConfiguration.class);
     when(scmConfiguration.provider()).thenReturn(scmProvider);
     underTest = new MetadataPublisher(projectInfo, inputModuleHierarchy, properties, qProfiles, cpdSettings,
-      pluginRepository, branches, scmRevision, forkDateSupplier, scmConfiguration);
+      pluginRepository, branches, scmRevision, forkDateSupplier, componentStore, scmConfiguration);
   }
 
   @Test
@@ -141,6 +141,7 @@ public class MetadataPublisherTest {
     assertThat(metadata.getProjectKey()).isEqualTo("root");
     assertThat(metadata.getModulesProjectRelativePathByKeyMap()).containsOnly(entry("module", "modulePath"), entry("root", ""));
     assertThat(metadata.getProjectVersion()).isEmpty();
+    assertThat(metadata.getNotAnalyzedFilesByLanguageCount()).isZero();
     assertThat(metadata.getQprofilesPerLanguageMap()).containsOnly(entry("java", org.sonar.scanner.protocol.output.ScannerReport.Metadata.QProfile.newBuilder()
       .setKey("q1")
       .setName("Q1")
@@ -148,15 +149,29 @@ public class MetadataPublisherTest {
       .setRulesUpdatedAt(date.getTime())
       .build()));
     assertThat(metadata.getPluginsByKey()).containsOnly(entry("java", org.sonar.scanner.protocol.output.ScannerReport.Metadata.Plugin.newBuilder()
-        .setKey("java")
-        .setUpdatedAt(12345)
-        .build()),
+      .setKey("java")
+      .setUpdatedAt(12345)
+      .build()),
       entry("php", org.sonar.scanner.protocol.output.ScannerReport.Metadata.Plugin.newBuilder()
         .setKey("php")
         .setUpdatedAt(45678)
         .build()));
   }
 
+  @Test
+  public void write_not_analysed_file_counts() throws Exception {
+    when(componentStore.getNotAnalysedFilesByLanguage()).thenReturn(ImmutableMap.of("c", 10, "cpp", 20));
+
+    File outputDir = temp.newFolder();
+    ScannerReportWriter writer = new ScannerReportWriter(outputDir);
+
+    underTest.publish(writer);
+
+    ScannerReportReader reader = new ScannerReportReader(outputDir);
+    ScannerReport.Metadata metadata = reader.readMetadata();
+    assertThat(metadata.getNotAnalyzedFilesByLanguageMap()).contains(entry("c", 10), entry("cpp", 20));
+  }
+
   @Test
   public void write_project_organization() throws Exception {
     when(properties.organizationKey()).thenReturn(Optional.of("SonarSource"));
index 4de345c222f7ea4628bebd12dfc943f5705f188e..de69cdaea765262c44b135dd461bf2471d994052 100644 (file)
@@ -27,6 +27,7 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.fs.internal.DefaultInputFile;
 import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
@@ -58,7 +59,7 @@ public class SourcePublisherTest {
       .build();
 
     DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(moduleKey, baseDir);
-    InputComponentStore componentStore = new InputComponentStore(mock(BranchConfiguration.class));
+    InputComponentStore componentStore = new InputComponentStore(mock(BranchConfiguration.class), mock(SonarRuntime.class));
     componentStore.put(moduleKey, inputFile);
 
     publisher = new SourcePublisher(componentStore);
index c427e5c9ccff5a2063427794b52911f817361434..4720972d39104a9b9299f99cadbe70be45acd5f4 100644 (file)
@@ -24,6 +24,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.slf4j.Logger;
+import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 import org.sonar.scanner.scan.filesystem.InputComponentStore;
@@ -42,7 +43,7 @@ public class QProfileVerifierTest {
 
   @Before
   public void before() {
-    store = new InputComponentStore(mock(BranchConfiguration.class));
+    store = new InputComponentStore(mock(BranchConfiguration.class), mock(SonarRuntime.class));
     profiles = mock(QualityProfiles.class);
     QProfile javaProfile = new QProfile("p1", "My Java profile", "java", null);
     when(profiles.findByLanguage("java")).thenReturn(javaProfile);
index 2a581f0c5ee0fbd22233ec07159955d733ced59e..b378685455256a1a7687cbc65ee9210d2b4003ac 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.scanner.scan;
 
 import java.util.Arrays;
 import org.junit.Test;
+import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.batch.fs.internal.DefaultInputModule;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
@@ -35,7 +36,7 @@ public class ModuleIndexerTest {
   private DefaultInputModuleHierarchy moduleHierarchy;
 
   public void createIndexer() {
-    InputComponentStore componentStore = new InputComponentStore(mock(BranchConfiguration.class));
+    InputComponentStore componentStore = new InputComponentStore(mock(BranchConfiguration.class), mock(SonarRuntime.class));
     moduleHierarchy = mock(DefaultInputModuleHierarchy.class);
     indexer = new ModuleIndexer(componentStore, moduleHierarchy);
   }
index abfbabcce30dddac55f0909e9d1c6a9341c33e27..f435cef1532628dc1d8b5d7daf132d988f4925d8 100644 (file)
@@ -24,9 +24,12 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.LinkedList;
 import java.util.List;
+import javax.annotation.Nullable;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.bootstrap.ProjectDefinition;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputFile.Status;
@@ -38,10 +41,16 @@ import org.sonar.api.batch.fs.internal.DefaultInputProject;
 import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
 import org.sonar.scanner.scan.branch.BranchConfiguration;
 
+import static java.util.Optional.ofNullable;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class InputComponentStoreTest {
+
+  private final SonarRuntime sonarRuntime = mock(SonarRuntime.class);
+
   @ClassRule
   public static TemporaryFolder temp = new TemporaryFolder();
 
@@ -60,7 +69,7 @@ public class InputComponentStoreTest {
     DefaultInputProject rootProject = TestInputFileBuilder.newDefaultInputProject(rootDef);
     DefaultInputModule subModule = TestInputFileBuilder.newDefaultInputModule(moduleDef);
 
-    InputComponentStore store = new InputComponentStore(mock(BranchConfiguration.class));
+    InputComponentStore store = new InputComponentStore(mock(BranchConfiguration.class), sonarRuntime);
     store.put(subModule);
 
     DefaultInputFile fooFile = new TestInputFileBuilder(rootModuleKey, "src/main/java/Foo.java")
@@ -95,13 +104,20 @@ public class InputComponentStoreTest {
   }
 
   static class InputComponentStoreTester extends InputComponentStore {
-    InputComponentStoreTester() {
-      super(mock(BranchConfiguration.class));
+    InputComponentStoreTester(SonarRuntime sonarRuntime) {
+      super(mock(BranchConfiguration.class), sonarRuntime);
+    }
+
+    InputFile addFile(String moduleKey, String relpath, @Nullable String language) {
+      TestInputFileBuilder fileBuilder = new TestInputFileBuilder(moduleKey, relpath);
+      ofNullable(language).ifPresent(fileBuilder::setLanguage);
+      DefaultInputFile file = fileBuilder.build();
+      put(moduleKey, file);
+      return file;
     }
 
-    InputFile addFile(String moduleKey, String relpath, String language) {
-      DefaultInputFile file = new TestInputFileBuilder(moduleKey, relpath)
-        .setLanguage(language)
+    InputFile addFile(String moduleKey, String relPath) {
+      DefaultInputFile file = new TestInputFileBuilder(moduleKey, relPath)
         .build();
       put(moduleKey, file);
       return file;
@@ -109,8 +125,8 @@ public class InputComponentStoreTest {
   }
 
   @Test
-  public void should_add_languages_per_module_and_globally() throws IOException {
-    InputComponentStoreTester tester = new InputComponentStoreTester();
+  public void should_add_languages_per_module_and_globally() {
+    InputComponentStoreTester tester = new InputComponentStoreTester(sonarRuntime);
 
     String mod1Key = "mod1";
     tester.addFile(mod1Key, "src/main/java/Foo.java", "java");
@@ -124,8 +140,8 @@ public class InputComponentStoreTest {
   }
 
   @Test
-  public void should_find_files_per_module_and_globally() throws IOException {
-    InputComponentStoreTester tester = new InputComponentStoreTester();
+  public void should_find_files_per_module_and_globally() {
+    InputComponentStoreTester tester = new InputComponentStoreTester(sonarRuntime);
 
     String mod1Key = "mod1";
     InputFile mod1File = tester.addFile(mod1Key, "src/main/java/Foo.java", "java");
@@ -137,4 +153,55 @@ public class InputComponentStoreTest {
     assertThat(tester.filesByModule(mod2Key)).containsExactly(mod2File);
     assertThat(tester.inputFiles()).containsExactlyInAnyOrder(mod1File, mod2File);
   }
+
+  @Test
+  public void stores_not_analysed_c_file_count_in_sq_community_edition() {
+    when(sonarRuntime.getEdition()).thenReturn(SonarEdition.COMMUNITY);
+    InputComponentStoreTester underTest = new InputComponentStoreTester(sonarRuntime);
+    String mod1Key = "mod1";
+    underTest.addFile(mod1Key, "src/main/java/Foo.java", "java");
+    underTest.addFile(mod1Key, "src/main/c/file1.c");
+    underTest.addFile(mod1Key, "src/main/c/file2.c");
+    String mod2Key = "mod2";
+    underTest.addFile(mod2Key, "src/main/groovy/Foo.groovy", "groovy");
+    underTest.addFile(mod2Key, "src/main/c/file3.c");
+
+    assertThat(underTest.getNotAnalysedFilesByLanguage()).hasSize(1);
+    assertThat(underTest.getNotAnalysedFilesByLanguage()).containsEntry("C", 3);
+  }
+
+  @Test
+  public void stores_not_analysed_cpp_file_count_in_sq_community_edition() {
+    when(sonarRuntime.getEdition()).thenReturn(SonarEdition.COMMUNITY);
+    InputComponentStoreTester underTest = new InputComponentStoreTester(sonarRuntime);
+    String mod1Key = "mod1";
+    underTest.addFile(mod1Key, "src/main/java/Foo.java", "java");
+    underTest.addFile(mod1Key, "src/main/c/file1.c");
+    underTest.addFile(mod1Key, "src/main/c/file2.cpp");
+    underTest.addFile(mod1Key, "src/main/c/file3.cxx");
+    underTest.addFile(mod1Key, "src/main/c/file4.c++");
+    underTest.addFile(mod1Key, "src/main/c/file5.cc");
+    underTest.addFile(mod1Key, "src/main/c/file6.CPP");
+    String mod2Key = "mod2";
+    underTest.addFile(mod2Key, "src/main/groovy/Foo.groovy", "groovy");
+    underTest.addFile(mod2Key, "src/main/c/file3.cpp");
+
+    assertThat(underTest.getNotAnalysedFilesByLanguage()).hasSize(2);
+    assertThat(underTest.getNotAnalysedFilesByLanguage()).containsEntry("C++", 6);
+  }
+
+  @Test
+  public void does_not_store_not_analysed_file_counts_in_sq_non_community_editions() {
+    when(sonarRuntime.getEdition()).thenReturn(SonarEdition.DEVELOPER);
+    InputComponentStoreTester underTest = new InputComponentStoreTester(sonarRuntime);
+    String mod1Key = "mod1";
+    underTest.addFile(mod1Key, "src/main/java/Foo.java", "java");
+    underTest.addFile(mod1Key, "src/main/java/file1.c");
+    underTest.addFile(mod1Key, "src/main/java/file2.c");
+    String mod2Key = "mod2";
+    underTest.addFile(mod2Key, "src/main/groovy/Foo.groovy", "groovy");
+    underTest.addFile(mod2Key, "src/main/groovy/file4.c");
+
+    assertThat(underTest.getNotAnalysedFilesByLanguage()).isEmpty();
+  }
 }
index 0b9e8b2571ab97ec3298e7e028000b80b570e353..522172db47f55d1ddb13915e3cd35aa793f850b9 100644 (file)
@@ -24,6 +24,7 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.sonar.api.SonarRuntime;
 import org.sonar.api.batch.fs.InputFile;
 import org.sonar.api.batch.fs.InputModule;
 import org.sonar.api.batch.fs.internal.SensorStrategy;
@@ -49,7 +50,7 @@ public class ModuleInputComponentStoreTest {
   @Before
   public void setUp() throws IOException {
     DefaultInputProject root = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder());
-    componentStore = new InputComponentStore(mock(BranchConfiguration.class));
+    componentStore = new InputComponentStore(mock(BranchConfiguration.class), mock(SonarRuntime.class));
   }
 
   @Test
index 7349fa688f826adb24572d8563aa9906f3a44e76..20b8f682017ac56b740216ed1d5b7de71bcc7332 100644 (file)
@@ -32,9 +32,12 @@ import java.util.Map;
 import java.util.Scanner;
 import javax.annotation.CheckForNull;
 import javax.swing.*;
-import javax.swing.UIManager.*;
-import javax.swing.event.*;
-import javax.swing.tree.*;
+import javax.swing.UIManager.LookAndFeelInfo;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeSelectionModel;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.core.util.CloseableIterator;
@@ -94,6 +97,8 @@ public class ScannerReportViewerApp {
   private JEditorPane cpdTextBlocksEditor;
   private JScrollPane significantCodeTab;
   private JEditorPane significantCodeEditor;
+  private JScrollPane metadataTab;
+  private JEditorPane metadataEditor;
 
   /**
    * Create the application.
@@ -187,6 +192,7 @@ public class ScannerReportViewerApp {
     updateAdHocRules();
     updateQualityProfiles();
     updatePlugins();
+    updateMetadata();
   }
 
   private void loadComponents() {
@@ -348,6 +354,21 @@ public class ScannerReportViewerApp {
     }
   }
 
+  private void updateMetadata() {
+    metadataEditor.setText("");
+
+    StringBuilder builder = new StringBuilder();
+    Metadata data = reader.readMetadata();
+    builder.append("Project key: ").append(data.getProjectKey()).append("\n");
+    builder.append("Project version: ").append(data.getProjectVersion()).append("\n");
+    builder.append("Scm revision ID: ").append(data.getScmRevisionId()).append("\n");
+    if (data.getNotAnalyzedFilesByLanguageCount() > 0) {
+      builder.append("Not analyzed files in project:").append("\n");
+      data.getNotAnalyzedFilesByLanguageMap().forEach((key, value) -> builder.append("   ").append(key).append(": ").append(value).append("\n"));
+    }
+    metadataEditor.setText(builder.toString());
+  }
+
   private void updateActiveRules() {
     activeRuleEditor.setText("");
 
@@ -588,6 +609,12 @@ public class ScannerReportViewerApp {
     significantCodeEditor = new JEditorPane();
     significantCodeTab.setViewportView(significantCodeEditor);
 
+    metadataTab = new JScrollPane();
+    tabbedPane.addTab("Metadata", null, metadataTab, null);
+
+    metadataEditor = new JEditorPane();
+    metadataTab.setViewportView(metadataEditor);
+
     treeScrollPane = new JScrollPane();
     treeScrollPane.setPreferredSize(new Dimension(200, 400));
     splitPane.setLeftComponent(treeScrollPane);
index b984bf7abbbb4690159a43d6b395963d5a556f48..3e3a1f803516a20104fbba32462f620b0f18495f 100644 (file)
@@ -58,6 +58,8 @@ message Metadata {
 
   int64 forkDate = 19;
 
+  map<string, int32> not_analyzed_files_by_language = 20;
+
   message QProfile {
     string key = 1;
     string name = 2;