Browse Source

SONAR-13867 Raise analysis warning in CE when scanner report has unanalysed C/C++ files

tags/8.5.0.37579
Michal Duda 3 years ago
parent
commit
1c53c91568

+ 111
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStep.java View File

@@ -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;
}
}

+ 1
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java View 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,


+ 160
- 0
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PerformNotAnalyzedFilesCheckStepTest.java View File

@@ -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());
}
}

+ 2
- 2
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistAnalysisWarningsStepTest.java View 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);
}
}

Loading…
Cancel
Save