aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorMichal Duda <michal.duda@sonarsource.com>2020-09-11 15:48:56 +0200
committersonartech <sonartech@sonarsource.com>2020-09-29 20:07:41 +0000
commit1c53c91568bc9af10ca78ae5aff7a1e79f255074 (patch)
treea8a8317a70c4049a131a6f3282763320fd1b3d54 /server
parent8a94f2ffc23369e675fceb34c03c98e1535d49d6 (diff)
downloadsonarqube-1c53c91568bc9af10ca78ae5aff7a1e79f255074.tar.gz
sonarqube-1c53c91568bc9af10ca78ae5aff7a1e79f255074.zip
SONAR-13867 Raise analysis warning in CE when scanner report has unanalysed C/C++ files
Diffstat (limited to 'server')
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStep.java111
-rw-r--r--server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java1
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStepTest.java160
-rw-r--r--server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisWarningsStepTest.java4
4 files changed, 274 insertions, 2 deletions
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
index 00000000000..217aeafe712
--- /dev/null
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStep.java
@@ -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;
+ }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java
index 9eda77e3c9a..cd708269303 100644
--- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java
+++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java
@@ -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
index 00000000000..130a7a519ed
--- /dev/null
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStepTest.java
@@ -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());
+ }
+}
diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisWarningsStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisWarningsStepTest.java
index b49c37fe7d1..1185859da3f 100644
--- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisWarningsStepTest.java
+++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisWarningsStepTest.java
@@ -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);
}
}