Skip to content

Commit

Permalink
SONARPY-2193: Update sonarlint-core.version to v10 (major) (#2068)
Browse files Browse the repository at this point in the history
  • Loading branch information
joke1196 authored Oct 14, 2024
1 parent 83dbc83 commit cbef8fd
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 84 deletions.
102 changes: 64 additions & 38 deletions ...m/sonar/python/it/plugin/IPythonTest.java → ...ython/it/plugin/SonarLintIPythonTest.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -27,88 +27,114 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonarsource.sonarlint.core.StandaloneSonarLintEngineImpl;
import org.sonarsource.sonarlint.core.analysis.AnalysisEngine;
import org.sonarsource.sonarlint.core.analysis.api.ActiveRule;
import org.sonarsource.sonarlint.core.analysis.api.AnalysisConfiguration;
import org.sonarsource.sonarlint.core.analysis.api.AnalysisEngineConfiguration;
import org.sonarsource.sonarlint.core.analysis.api.ClientInputFile;
import org.sonarsource.sonarlint.core.analysis.api.ClientModuleFileSystem;
import org.sonarsource.sonarlint.core.analysis.api.ClientModuleInfo;
import org.sonarsource.sonarlint.core.analysis.api.Issue;
import org.sonarsource.sonarlint.core.analysis.api.WithTextRange;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneAnalysisConfiguration;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneGlobalConfiguration;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneSonarLintEngine;
import org.sonarsource.sonarlint.core.commons.IssueSeverity;
import org.sonarsource.sonarlint.core.commons.Language;
import org.sonarsource.sonarlint.core.commons.log.ClientLogOutput;
import org.sonarsource.sonarlint.core.analysis.command.AnalyzeCommand;
import org.sonarsource.sonarlint.core.analysis.command.RegisterModuleCommand;
import org.sonarsource.sonarlint.core.commons.api.SonarLanguage;
import org.sonarsource.sonarlint.core.commons.log.LogOutput;
import org.sonarsource.sonarlint.core.commons.log.LogOutput.Level;
import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger;
import org.sonarsource.sonarlint.core.commons.progress.ProgressMonitor;
import org.sonarsource.sonarlint.core.plugin.commons.PluginsLoader;

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

class IPythonTest {
class SonarLintIPythonTest {

@TempDir
public static Path TEMP;
public static Path temp;

private static StandaloneSonarLintEngine sonarlintEngine;
private static AnalysisEngine sonarlintEngine;
private final ProgressMonitor progressMonitor = new ProgressMonitor(null);

@BeforeAll
static void prepare() throws Exception {
StandaloneGlobalConfiguration sonarLintConfig = StandaloneGlobalConfiguration.builder()
.addPlugin(TestsUtils.PLUGIN_LOCATION.getFile().toPath())
.setSonarLintUserHome(TEMP)
.addEnabledLanguage(Language.IPYTHON)
.setLogOutput((formattedMessage, level) -> {
/* Don't pollute logs */ })
.setModulesProvider(Collections::emptyList)
static void prepare() {
var sonarLintConfig = AnalysisEngineConfiguration.builder()
.setWorkDir(temp)
.build();
sonarlintEngine = new StandaloneSonarLintEngineImpl(sonarLintConfig);

var logOutput = new LogOutput() {
@Override
public void log(String formattedMessage, Level level, @Nullable String stacktrace) {
/* Don't pollute logs */
}
};
SonarLintLogger.setTarget(logOutput);
var pluginJarLocation = Set.of(TestsUtils.PLUGIN_LOCATION.getFile().toPath());
var enabledLanguages = Set.of(SonarLanguage.IPYTHON);
var pluginConfiguration = new PluginsLoader.Configuration(pluginJarLocation, enabledLanguages, false, Optional.empty());
var pluginLoader = new PluginsLoader().load(pluginConfiguration, Set.of());

sonarlintEngine = new AnalysisEngine(sonarLintConfig, pluginLoader.getLoadedPlugins(), logOutput);
}

@AfterAll
static void stop() {
SonarLintLogger.setTarget(null);
sonarlintEngine.stop();
}

@Test
void shouldRaiseIssues() {
void shouldRaiseIssues() throws InterruptedException, ExecutionException {
var inputFile = createInputFile(Path.of("projects/ipynb_project/file1.ipynb"), "file1.ipynb", false);
var issues = new ArrayList<Issue>();

var configuration = StandaloneAnalysisConfiguration.builder()
var configuration = AnalysisConfiguration.builder()
.setBaseDir(Path.of("projects/ipynb_project"))
.addInputFile(inputFile)
.setModuleKey("myModule")
.addActiveRules(new ActiveRule("ipython:PrintStatementUsage", SonarLanguage.IPYTHON.name()),
new ActiveRule("ipython:S1172", SonarLanguage.IPYTHON.name()),
new ActiveRule("ipython:S930", SonarLanguage.IPYTHON.name()),
new ActiveRule("ipython:S1542", SonarLanguage.IPYTHON.name()),
new ActiveRule("ipython:BackticksUsage", SonarLanguage.IPYTHON.name()))
.build();

var logsByLevel = new HashMap<ClientLogOutput.Level, List<String>>();
var logsByLevel = new HashMap<Level, List<String>>();
var logOutput = createClientLogOutput(logsByLevel);
var clientFileSystem = createClientFileSystem(inputFile);
sonarlintEngine.declareModule(new ClientModuleInfo("myModule", clientFileSystem));
sonarlintEngine.analyze(configuration, issues::add, logOutput, null);

sonarlintEngine.post(new RegisterModuleCommand(new ClientModuleInfo("myModule", clientFileSystem)), progressMonitor).get();
var command = new AnalyzeCommand("myModule", configuration, issues::add, logOutput);
sonarlintEngine.post(command, progressMonitor).get();
assertThat(issues)
.extracting(Issue::getRuleKey, WithTextRange::getStartLine, i -> i.getInputFile().uri(), Issue::getSeverity)
.extracting(Issue::getRuleKey, WithTextRange::getStartLine, i -> i.getInputFile().uri())
.containsOnly(
tuple("ipython:PrintStatementUsage", 32, inputFile.uri(), IssueSeverity.MAJOR),
tuple("ipython:S1172", 40, inputFile.uri(), IssueSeverity.MAJOR),
tuple("ipython:S930", 41, inputFile.uri(), IssueSeverity.BLOCKER),
tuple("ipython:S1172", 42, inputFile.uri(), IssueSeverity.MAJOR),
tuple("ipython:S1542", 57, inputFile.uri(), IssueSeverity.MAJOR),
tuple("ipython:BackticksUsage", 58, inputFile.uri(), IssueSeverity.BLOCKER)
);
tuple("ipython:PrintStatementUsage", 32, inputFile.uri()),
tuple("ipython:S1172", 40, inputFile.uri()),
tuple("ipython:S930", 41, inputFile.uri()),
tuple("ipython:S1172", 42, inputFile.uri()),
tuple("ipython:S1542", 57, inputFile.uri()),
tuple("ipython:BackticksUsage", 58, inputFile.uri()));
}

private static ClientLogOutput createClientLogOutput(Map<ClientLogOutput.Level, List<String>> logsByLevel) {
return (s, level) -> logsByLevel.computeIfAbsent(level, (k) -> new ArrayList<>()).add(s);
private static LogOutput createClientLogOutput(Map<Level, List<String>> logsByLevel) {
return new LogOutput() {
@Override
public void log(String formattedMessage, Level level, @Nullable String stacktrace) {
logsByLevel.computeIfAbsent(level, k -> new ArrayList<>()).add(formattedMessage);
}
};
}

private static ClientModuleFileSystem createClientFileSystem(ClientInputFile... inputFiles) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,81 +28,101 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.apache.commons.io.FileUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonarsource.sonarlint.core.StandaloneSonarLintEngineImpl;
import org.sonarsource.sonarlint.core.analysis.AnalysisEngine;
import org.sonarsource.sonarlint.core.analysis.api.ActiveRule;
import org.sonarsource.sonarlint.core.analysis.api.AnalysisConfiguration;
import org.sonarsource.sonarlint.core.analysis.api.AnalysisEngineConfiguration;
import org.sonarsource.sonarlint.core.analysis.api.ClientInputFile;
import org.sonarsource.sonarlint.core.analysis.api.ClientModuleFileSystem;
import org.sonarsource.sonarlint.core.analysis.api.ClientModuleInfo;
import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneAnalysisConfiguration;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneGlobalConfiguration;
import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneSonarLintEngine;
import org.sonarsource.sonarlint.core.commons.IssueSeverity;
import org.sonarsource.sonarlint.core.commons.Language;
import org.sonarsource.sonarlint.core.commons.log.ClientLogOutput;
import org.sonarsource.sonarlint.core.analysis.api.Issue;
import org.sonarsource.sonarlint.core.analysis.command.AnalyzeCommand;
import org.sonarsource.sonarlint.core.analysis.command.RegisterModuleCommand;
import org.sonarsource.sonarlint.core.commons.api.SonarLanguage;
import org.sonarsource.sonarlint.core.commons.log.LogOutput;
import org.sonarsource.sonarlint.core.commons.log.LogOutput.Level;
import org.sonarsource.sonarlint.core.commons.log.SonarLintLogger;
import org.sonarsource.sonarlint.core.commons.progress.ProgressMonitor;
import org.sonarsource.sonarlint.core.plugin.commons.PluginsLoader;

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

class SonarLintTest {

@TempDir
public static Path TEMP;
public static Path temp;

private static StandaloneSonarLintEngine sonarlintEngine;
private static AnalysisEngine sonarlintEngine;
private final ProgressMonitor progressMonitor = new ProgressMonitor(null);

private static File baseDir;

@BeforeAll
static void prepare() throws Exception {
StandaloneGlobalConfiguration sonarLintConfig = StandaloneGlobalConfiguration.builder()
.addPlugin(TestsUtils.PLUGIN_LOCATION.getFile().toPath())
.setSonarLintUserHome(TEMP)
.addEnabledLanguage(Language.PYTHON)
.setLogOutput((formattedMessage, level) -> {
/* Don't pollute logs */ })
.setModulesProvider(Collections::emptyList)
static void prepare() {
var sonarLintConfig = AnalysisEngineConfiguration.builder()
.setWorkDir(temp)
.build();
sonarlintEngine = new StandaloneSonarLintEngineImpl(sonarLintConfig);
baseDir = TEMP.toFile();

var logOutput = new LogOutput() {
@Override
public void log(String formattedMessage, Level level, @Nullable String stacktrace) {
/* Don't pollute logs */
}
};
SonarLintLogger.setTarget(logOutput);
var pluginJarLocation = Set.of(TestsUtils.PLUGIN_LOCATION.getFile().toPath());
var enabledLanguages = Set.of(SonarLanguage.PYTHON);
var pluginConfiguration = new PluginsLoader.Configuration(pluginJarLocation, enabledLanguages, false, Optional.empty());
var pluginLoader = new PluginsLoader().load(pluginConfiguration, Set.of());

sonarlintEngine = new AnalysisEngine(sonarLintConfig, pluginLoader.getLoadedPlugins(), logOutput);
baseDir = temp.toFile();
}

@AfterAll
static void stop() {
SonarLintLogger.setTarget(null);
sonarlintEngine.stop();
}

@Test
void should_raise_issues() throws IOException {
void should_raise_issues() throws IOException, InterruptedException, ExecutionException {
ClientInputFile inputFile = prepareInputFile("foo.py",
"def fooBar():\n"
+ " `1` \n"
+ " `1` #NOSONAR\n",
false);

List<Issue> issues = new ArrayList<>();
StandaloneAnalysisConfiguration configuration =
StandaloneAnalysisConfiguration.builder()
.setBaseDir(baseDir.toPath())
.addInputFile(inputFile)
.setModuleKey("myModule")
.build();

Map<ClientLogOutput.Level, List<String>> logsByLevel = new HashMap<>();
ClientLogOutput logOutput = (s, level) -> {
List<String> logs = logsByLevel.getOrDefault(level, new ArrayList<>());
logs.add(s);
logsByLevel.putIfAbsent(level, logs);
var configuration = AnalysisConfiguration.builder()
.setBaseDir(baseDir.toPath())
.addInputFile(inputFile)
.addActiveRules(
new ActiveRule("python:S1542", SonarLanguage.PYTHON.name()),
new ActiveRule("python:BackticksUsage", SonarLanguage.PYTHON.name()))
.build();

Map<Level, List<String>> logsByLevel = new HashMap<>();
LogOutput logOutput = new LogOutput() {
@Override
public void log(String formattedMessage, Level level, @Nullable String stacktrace) {
logsByLevel.computeIfAbsent(level, k -> new ArrayList<>()).add(formattedMessage);
}
};
ClientModuleFileSystem clientFileSystem = new ClientModuleFileSystem() {
@Override
Expand All @@ -115,13 +135,14 @@ public Stream<ClientInputFile> files() {
return Stream.of(inputFile);
}
};
sonarlintEngine.declareModule(new ClientModuleInfo("myModule", clientFileSystem));
sonarlintEngine.analyze(configuration, issues::add, logOutput, null);

assertThat(logsByLevel.get(ClientLogOutput.Level.WARN)).containsExactly("No workDir in SonarLint");
assertThat(issues).extracting("ruleKey", "startLine", "inputFile.path", "severity").containsOnly(
tuple("python:BackticksUsage", 2, inputFile.uri().getPath(), IssueSeverity.BLOCKER),
tuple("python:S1542", 1, inputFile.uri().getPath(), IssueSeverity.MAJOR));
sonarlintEngine.post(new RegisterModuleCommand(new ClientModuleInfo("myModule", clientFileSystem)), progressMonitor).get();
var command = new AnalyzeCommand("myModule", configuration, issues::add, logOutput);
sonarlintEngine.post(command, progressMonitor).get();

assertThat(logsByLevel.get(Level.WARN)).containsExactly("No workDir in SonarLint");
assertThat(issues).extracting("ruleKey", "textRange.startLine", "inputFile.path").containsOnly(
tuple("python:BackticksUsage", 2, inputFile.uri().getPath()),
tuple("python:S1542", 1, inputFile.uri().getPath()));
}

private static ClientInputFile prepareInputFile(String relativePath, String content, final boolean isTest) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
CPDTest.class,
CustomRulesTest.class,
Flake8ReportTest.class,
IPythonTest.class,
SonarLintIPythonTest.class,
MetricsTest.class,
MypyReportTest.class,
NoSonarTest.class,
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
<sonar.api.version>10.11.0.2468</sonar.api.version>
<sonar.orchestrator.version>5.0.0.2065</sonar.orchestrator.version>
<sonar-analyzer-commons.version>2.14.0.3087</sonar-analyzer-commons.version>
<sonarlint-core.version>8.19.0.72745</sonarlint-core.version>
<sonarlint-core.version>10.7.1.79146</sonarlint-core.version>
<sslr.version>1.24.0.633</sslr.version>
<protobuf.version>4.28.2</protobuf.version>
<woodstox.version>6.2.7</woodstox.version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.internal.apachecommons.lang.StringUtils;
import org.sonar.api.internal.apachecommons.lang3.StringUtils;
import org.sonar.python.IPythonLocation;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
import org.sonarsource.sonarlint.core.analysis.api.ClientInputFile;
import org.sonarsource.sonarlint.core.analysis.container.analysis.filesystem.FileMetadata;
import org.sonarsource.sonarlint.core.analysis.container.analysis.filesystem.SonarLintInputFile;
import org.sonarsource.sonarlint.core.commons.Language;
import org.sonarsource.sonarlint.core.commons.api.SonarLanguage;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -1404,7 +1404,7 @@ private void setup_quickfix_sensor() throws IOException {

SonarLintInputFile sonarFile = new SonarLintInputFile(clientFile, metadataGenerator);
sonarFile.setType(Type.MAIN);
sonarFile.setLanguage(Language.PYTHON);
sonarFile.setLanguage(SonarLanguage.PYTHON);

context.fileSystem().add(sonarFile);
sensor().execute(context);
Expand Down

0 comments on commit cbef8fd

Please sign in to comment.