]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13867 Raise analysis warning in CE when scanner report has unanalysed C/C+...
authorMichal Duda <michal.duda@sonarsource.com>
Fri, 11 Sep 2020 13:48:56 +0000 (15:48 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 29 Sep 2020 20:07:41 +0000 (20:07 +0000)
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStep.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStepTest.java [new file with mode: 0644]
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisWarningsStepTest.java

diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStep.java
new file mode 100644 (file)
index 0000000..217aeaf
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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.ce.task.projectanalysis.step;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+import org.sonar.api.utils.System2;
+import org.sonar.ce.task.log.CeTaskMessages;
+import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
+import org.sonar.ce.task.step.ComputationStep;
+import org.sonar.core.platform.EditionProvider;
+import org.sonar.core.platform.PlatformEditionProvider;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.String.format;
+
+/**
+ * Check if there are files that could be analyzed with a higher SQ edition.
+ */
+public class PerformNotAnalyzedFilesCheckStep implements ComputationStep {
+  static final String DESCRIPTION = "Check upgrade possibility for not analyzed code files.";
+
+  private static final String LANGUAGE_UPGRADE_MESSAGE = "%s file(s) detected during the last analysis. %s code cannot be analyzed with SonarQube " +
+    "community edition. Please consider <a href=\"https://www.sonarqube.org/trial-request/developer-edition/?referrer=sonarqube-cpp\">upgrading to " +
+    "the Developer Edition</a> to analyze this language.";
+
+  private final BatchReportReader reportReader;
+  private final CeTaskMessages ceTaskMessages;
+  private final PlatformEditionProvider editionProvider;
+  private final System2 system;
+
+  public PerformNotAnalyzedFilesCheckStep(BatchReportReader reportReader, CeTaskMessages ceTaskMessages, PlatformEditionProvider editionProvider,
+    System2 system) {
+    this.reportReader = reportReader;
+    this.ceTaskMessages = ceTaskMessages;
+    this.editionProvider = editionProvider;
+    this.system = system;
+  }
+
+  @Override
+  public void execute(Context context) {
+    editionProvider.get().ifPresent(edition -> {
+      if (!edition.equals(EditionProvider.Edition.COMMUNITY)) {
+        return;
+      }
+
+      Map<String, Integer> filesPerLanguage = reportReader.readMetadata().getNotAnalyzedFilesByLanguageMap()
+        .entrySet()
+        .stream()
+        .filter(entry -> entry.getValue() > 0)
+        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+      if (filesPerLanguage.isEmpty()) {
+        return;
+      }
+
+      ceTaskMessages.add(constructMessage(filesPerLanguage));
+    });
+  }
+
+  private CeTaskMessages.Message constructMessage(Map<String, Integer> filesPerLanguage) {
+    checkNotNull(filesPerLanguage);
+    checkArgument(filesPerLanguage.size() > 0);
+
+    SortedMap<String, Integer> sortedLanguageMap = new TreeMap<>(filesPerLanguage);
+    Iterator<Map.Entry<String, Integer>> iterator = sortedLanguageMap.entrySet().iterator();
+    Map.Entry<String, Integer> firstLanguage = iterator.next();
+    StringBuilder languageLabel = new StringBuilder(firstLanguage.getKey());
+    StringBuilder fileCountLabel = new StringBuilder(format("%s %s", firstLanguage.getValue(), firstLanguage.getKey()));
+    while (iterator.hasNext()) {
+      Map.Entry<String, Integer> nextLanguage = iterator.next();
+      if (iterator.hasNext()) {
+        languageLabel.append(", ");
+        fileCountLabel.append(", ");
+      } else {
+        languageLabel.append(" and ");
+        fileCountLabel.append(" and ");
+      }
+      languageLabel.append(nextLanguage.getKey());
+      fileCountLabel.append(format("%s %s", nextLanguage.getValue(), nextLanguage.getKey()));
+    }
+
+    return new CeTaskMessages.Message(format(LANGUAGE_UPGRADE_MESSAGE, fileCountLabel, languageLabel), system.now());
+  }
+
+  @Override
+  public String getDescription() {
+    return DESCRIPTION;
+  }
+}
index 9eda77e3c9a0acf69779adb904247f9ae2264083..cd708269303da2f1ae7e3af861b0c51e199588b3 100644 (file)
@@ -38,6 +38,7 @@ public class ReportComputationSteps extends AbstractComputationSteps {
   private static final List<Class<? extends ComputationStep>> STEPS = Arrays.asList(
     ExtractReportStep.class,
     PersistScannerContextStep.class,
+    PerformNotAnalyzedFilesCheckStep.class,
     PersistAnalysisWarningsStep.class,
     GenerateAnalysisUuid.class,
 
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStepTest.java
new file mode 100644 (file)
index 0000000..130a7a5
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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.ce.task.projectanalysis.step;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.Optional;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.sonar.api.utils.System2;
+import org.sonar.ce.task.log.CeTaskMessages;
+import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
+import org.sonar.ce.task.step.TestComputationStepContext;
+import org.sonar.core.platform.EditionProvider;
+import org.sonar.core.platform.PlatformEditionProvider;
+import org.sonar.scanner.protocol.output.ScannerReport;
+
+import static com.google.common.collect.ImmutableList.of;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class PerformNotAnalyzedFilesCheckStepTest {
+
+  @Rule
+  public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+
+  private final PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
+  private final CeTaskMessages ceTaskMessages = mock(CeTaskMessages.class);
+  private final PerformNotAnalyzedFilesCheckStep underTest = new PerformNotAnalyzedFilesCheckStep(reportReader, ceTaskMessages, editionProvider, System2.INSTANCE);
+
+  @Test
+  public void getDescription() {
+    assertThat(underTest.getDescription()).isEqualTo(PerformNotAnalyzedFilesCheckStep.DESCRIPTION);
+  }
+
+  @Test
+  public void execute_adds_warning_in_SQ_community_edition_if_there_are_c_or_cpp_files() {
+    when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
+    ScannerReport.AnalysisWarning warning1 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 1").build();
+    ScannerReport.AnalysisWarning warning2 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 2").build();
+    ImmutableList<ScannerReport.AnalysisWarning> warnings = of(warning1, warning2);
+    reportReader.setAnalysisWarnings(warnings);
+    reportReader.setMetadata(ScannerReport.Metadata.newBuilder()
+      .putNotAnalyzedFilesByLanguage("C++", 20)
+      .putNotAnalyzedFilesByLanguage("C", 10)
+      .putNotAnalyzedFilesByLanguage("SomeLang", 1000)
+      .build());
+    ArgumentCaptor<CeTaskMessages.Message> argumentCaptor = ArgumentCaptor.forClass(CeTaskMessages.Message.class);
+
+    underTest.execute(new TestComputationStepContext());
+
+    verify(ceTaskMessages, times(1)).add(argumentCaptor.capture());
+    List<CeTaskMessages.Message> messages = argumentCaptor.getAllValues();
+    assertThat(messages).extracting(CeTaskMessages.Message::getText).containsExactly(
+      "10 C, 20 C++ and 1000 SomeLang file(s) detected during the last analysis. C, C++ and SomeLang code cannot be analyzed with SonarQube community " +
+        "edition. Please consider <a href=\"https://www.sonarqube.org/trial-request/developer-edition/?referrer=sonarqube-cpp\">upgrading to the Developer " +
+        "Edition</a> to analyze this language.");
+  }
+
+  @Test
+  public void execute_adds_warning_in_SQ_community_edition_if_there_are_c_files() {
+    when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
+    reportReader.setMetadata(ScannerReport.Metadata.newBuilder()
+      .putNotAnalyzedFilesByLanguage("C", 10)
+      .build());
+    ArgumentCaptor<CeTaskMessages.Message> argumentCaptor = ArgumentCaptor.forClass(CeTaskMessages.Message.class);
+
+    underTest.execute(new TestComputationStepContext());
+
+    verify(ceTaskMessages, times(1)).add(argumentCaptor.capture());
+    List<CeTaskMessages.Message> messages = argumentCaptor.getAllValues();
+    assertThat(messages).extracting(CeTaskMessages.Message::getText).containsExactly(
+      "10 C file(s) detected during the last analysis. C code cannot be analyzed with SonarQube community " +
+        "edition. Please consider <a href=\"https://www.sonarqube.org/trial-request/developer-edition/?referrer=sonarqube-cpp\">upgrading to the Developer " +
+        "Edition</a> to analyze this language.");
+  }
+
+  @Test
+  public void execute_adds_warning_in_SQ_community_edition_if_there_are_cpp_files() {
+    when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
+    reportReader.setMetadata(ScannerReport.Metadata.newBuilder()
+      .putNotAnalyzedFilesByLanguage("C++", 9)
+      .build());
+    ArgumentCaptor<CeTaskMessages.Message> argumentCaptor = ArgumentCaptor.forClass(CeTaskMessages.Message.class);
+
+    underTest.execute(new TestComputationStepContext());
+
+    verify(ceTaskMessages, times(1)).add(argumentCaptor.capture());
+    List<CeTaskMessages.Message> messages = argumentCaptor.getAllValues();
+    assertThat(messages).extracting(CeTaskMessages.Message::getText).containsExactly(
+      "9 C++ file(s) detected during the last analysis. C++ code cannot be analyzed with SonarQube community " +
+        "edition. Please consider <a href=\"https://www.sonarqube.org/trial-request/developer-edition/?referrer=sonarqube-cpp\">upgrading to the Developer " +
+        "Edition</a> to analyze this language.");
+  }
+
+  @Test
+  public void execute_does_not_add_a_warning_in_SQ_community_edition_if_cpp_files_in_report_is_zero() {
+    when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
+    ScannerReport.AnalysisWarning warning1 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 1").build();
+    ScannerReport.AnalysisWarning warning2 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 2").build();
+    ImmutableList<ScannerReport.AnalysisWarning> warnings = of(warning1, warning2);
+    reportReader.setAnalysisWarnings(warnings);
+    reportReader.setMetadata(ScannerReport.Metadata.newBuilder().putNotAnalyzedFilesByLanguage("C++", 0).build());
+
+    underTest.execute(new TestComputationStepContext());
+
+    verify(ceTaskMessages, never()).add(any());
+  }
+
+  @Test
+  public void execute_does_not_add_a_warning_in_SQ_community_edition_if_no_c_or_cpp_files_2() {
+    when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.COMMUNITY));
+    ScannerReport.AnalysisWarning warning1 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 1").build();
+    ScannerReport.AnalysisWarning warning2 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 2").build();
+    ImmutableList<ScannerReport.AnalysisWarning> warnings = of(warning1, warning2);
+    reportReader.setAnalysisWarnings(warnings);
+    reportReader.setMetadata(ScannerReport.Metadata.newBuilder().build());
+
+    underTest.execute(new TestComputationStepContext());
+
+    verify(ceTaskMessages, never()).add(any());
+  }
+
+  @Test
+  public void execute_does_not_add_a_warning_in_SQ_non_community_edition() {
+    when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.ENTERPRISE));
+    ScannerReport.AnalysisWarning warning1 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 1").build();
+    ScannerReport.AnalysisWarning warning2 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 2").build();
+    ImmutableList<ScannerReport.AnalysisWarning> warnings = of(warning1, warning2);
+    reportReader.setAnalysisWarnings(warnings);
+    reportReader.setMetadata(ScannerReport.Metadata.newBuilder().putNotAnalyzedFilesByLanguage("C++", 20).build());
+
+    underTest.execute(new TestComputationStepContext());
+
+    verify(ceTaskMessages, never()).add(any());
+  }
+}
index b49c37fe7d1aa5c50b4ad08b417511c2406b92b3..1185859da3f8088facc2ed1c32ee5b83219305c3 100644 (file)
@@ -34,7 +34,7 @@ import static java.util.Collections.emptyList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
 
 public class PersistAnalysisWarningsStepTest {
 
@@ -70,6 +70,6 @@ public class PersistAnalysisWarningsStepTest {
 
     underTest.execute(new TestComputationStepContext());
 
-    verifyZeroInteractions(ceTaskMessages);
+    verifyNoInteractions(ceTaskMessages);
   }
 }