aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-css-plugin
diff options
context:
space:
mode:
authorElena Vilchik2019-06-07 17:35:05 +0200
committerTibor Blenessy2019-06-07 17:35:05 +0200
commit45c1d35f0a132b257c8aa419eb981d0b9198bd2f (patch)
treed534e9ecf372758916c78576829dc86006c81711 /sonar-css-plugin
parentac5b495929efed77f9bd954bd34a34b934d8da3b (diff)
downloadsonar-css-45c1d35f0a132b257c8aa419eb981d0b9198bd2f.tar.bz2
Reuse logic from SonarJS to discover node executable (#173)
* Reuse logic from SonarJS to discover node executable * change min size * Fix lookup of node from maven plugin on Win
Diffstat (limited to 'sonar-css-plugin')
-rw-r--r--sonar-css-plugin/pom.xml18
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java10
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRuleSensor.java99
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/ExternalProcessStreamConsumer.java68
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java6
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintCommandProvider.java52
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java8
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRuleSensorTest.java109
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintCommandProviderTest.java42
-rw-r--r--sonar-css-plugin/src/test/resources/executables/invalidNodeVersion.js1
10 files changed, 109 insertions, 304 deletions
diff --git a/sonar-css-plugin/pom.xml b/sonar-css-plugin/pom.xml
index 4a6a213..a1645e5 100644
--- a/sonar-css-plugin/pom.xml
+++ b/sonar-css-plugin/pom.xml
@@ -37,6 +37,10 @@
<artifactId>sonar-analyzer-commons</artifactId>
</dependency>
<dependency>
+ <groupId>org.sonarsource.javascript</groupId>
+ <artifactId>nodejs-utils</artifactId>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
@@ -127,8 +131,8 @@
<configuration>
<rules>
<requireFilesSize>
- <minsize>6500000</minsize>
- <maxsize>7000000</maxsize>
+ <minsize>6800000</minsize>
+ <maxsize>8000000</maxsize>
<files>
<file>${project.build.directory}/${project.build.finalName}.jar</file>
</files>
@@ -167,6 +171,16 @@
</plugin>
<plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <environmentVariables>
+ <!-- modify the path to include node installed with frontend plugin -->
+ <PATH>target${file.separator}node${path.separator}${env.PATH}</PATH>
+ </environmentVariables>
+ </configuration>
+ </plugin>
+
+ <plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java
index 6f78be1..9e78205 100644
--- a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java
@@ -37,7 +37,7 @@ public class CssPlugin implements Plugin {
public static final String STYLELINT_REPORT_PATHS = "sonar.css.stylelint.reportPaths";
public static final String STYLELINT_REPORT_PATHS_DEFAULT_VALUE = "";
- public static final String NODE_EXECUTABLE = "sonar.css.node";
+ public static final String FORMER_NODE_EXECUTABLE = "sonar.css.node";
private static final String CSS_CATEGORY = "CSS";
private static final String LINTER_SUBCATEGORY = "Popular Rule Engines";
@@ -66,14 +66,6 @@ public class CssPlugin implements Plugin {
.category(CSS_CATEGORY)
.onQualifiers(Qualifiers.PROJECT)
.multiValues(true)
- .build(),
-
- PropertyDefinition.builder(NODE_EXECUTABLE)
- .name("Node.js executable")
- .description("Path to the Node.js executable that will be used to run the analysis of CSS files. When not set, expects 'node' to be in the path.")
- .subCategory(GENERAL_SUBCATEGORY)
- .category(CSS_CATEGORY)
- .hidden()
.build()
);
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRuleSensor.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRuleSensor.java
index 2b268cd..82e6306 100644
--- a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRuleSensor.java
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRuleSensor.java
@@ -31,7 +31,6 @@ import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
-import org.apache.commons.io.IOUtils;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.rule.CheckFactory;
@@ -47,33 +46,36 @@ import org.sonar.css.plugin.CssRules.StylelintConfig;
import org.sonar.css.plugin.StylelintReport.Issue;
import org.sonar.css.plugin.StylelintReport.IssuesPerFile;
import org.sonar.css.plugin.bundle.BundleHandler;
+import org.sonarsource.nodejs.NodeCommand;
+import org.sonarsource.nodejs.NodeCommandException;
public class CssRuleSensor implements Sensor {
private static final Logger LOG = Loggers.get(CssRuleSensor.class);
- private static final int MIN_NODE_VERSION = 6;
- private static final String WARNING_PREFIX = "CSS files were not analyzed. ";
private final BundleHandler bundleHandler;
private final CssRules cssRules;
private final LinterCommandProvider linterCommandProvider;
@Nullable
private final AnalysisWarningsWrapper analysisWarnings;
- private final ExternalProcessStreamConsumer externalProcessStreamConsumer = new ExternalProcessStreamConsumer();
- public CssRuleSensor(BundleHandler bundleHandler,
- CheckFactory checkFactory,
- LinterCommandProvider linterCommandProvider,
- @Nullable AnalysisWarningsWrapper analysisWarnings) {
+ public CssRuleSensor(
+ BundleHandler bundleHandler,
+ CheckFactory checkFactory,
+ LinterCommandProvider linterCommandProvider,
+ @Nullable AnalysisWarningsWrapper analysisWarnings
+ ) {
this.bundleHandler = bundleHandler;
this.linterCommandProvider = linterCommandProvider;
this.cssRules = new CssRules(checkFactory);
this.analysisWarnings = analysisWarnings;
}
- public CssRuleSensor(BundleHandler bundleHandler,
- CheckFactory checkFactory,
- LinterCommandProvider linterCommandProvider) {
+ public CssRuleSensor(
+ BundleHandler bundleHandler,
+ CheckFactory checkFactory,
+ LinterCommandProvider linterCommandProvider
+ ) {
this(bundleHandler, checkFactory, linterCommandProvider, null);
}
@@ -86,39 +88,38 @@ public class CssRuleSensor implements Sensor {
@Override
public void execute(SensorContext context) {
+ // fixme add log and UI warn when old property is provided
+
if (cssRules.isEmpty()) {
LOG.warn("No rules are activated in CSS Quality Profile");
return;
}
- if (!checkCompatibleNodeVersion(context)) {
- return;
- }
-
File deployDestination = context.fileSystem().workDir();
- bundleHandler.deployBundle(deployDestination);
- String[] commandParts = linterCommandProvider.commandParts(deployDestination, context);
try {
- ProcessBuilder processBuilder = new ProcessBuilder(commandParts);
+ bundleHandler.deployBundle(deployDestination);
createLinterConfig(deployDestination);
- Process process = processBuilder.start();
StringBuilder output = new StringBuilder();
- externalProcessStreamConsumer.consumeStream(process.getInputStream(), output::append);
- externalProcessStreamConsumer.consumeStream(process.getErrorStream(), LOG::error);
- if (isSuccessful(process)) {
+
+ NodeCommand nodeCommand = linterCommandProvider.nodeCommand(deployDestination, context, output::append, LOG::error);
+ LOG.debug("Starting process: " + nodeCommand.toString());
+ nodeCommand.start();
+
+ if (isSuccessful(nodeCommand.waitFor())) {
saveIssues(context, output.toString());
}
+ } catch (NodeCommandException e) {
+ LOG.error(e.getMessage() + " No CSS files will be analyzed.", e);
+ if (analysisWarnings != null) {
+ analysisWarnings.addUnique("CSS files were not analyzed. " + e.getMessage());
+ }
} catch (Exception e) {
- LOG.error("Failed to run external linting process " + String.join(" ", commandParts), e);
- } finally {
- externalProcessStreamConsumer.shutdownNow();
+ LOG.error("Failed to run external linting process", e);
}
}
- private boolean isSuccessful(Process process) throws InterruptedException {
- int exitValue = process.waitFor();
- externalProcessStreamConsumer.await();
+ private boolean isSuccessful(int exitValue) {
// exit codes 0 and 2 are expected. 0 - means no issues were found, 2 - means that at least one "error-level" rule found issue
// see https://github.com/stylelint/stylelint/blob/master/docs/user-guide/cli.md#exit-codes
boolean isSuccessful = exitValue == 0 || exitValue == 2;
@@ -128,48 +129,6 @@ public class CssRuleSensor implements Sensor {
return isSuccessful;
}
- private boolean checkCompatibleNodeVersion(SensorContext context) {
- String nodeExecutable = linterCommandProvider.nodeExecutable(context.config());
- LOG.debug("Checking node version");
- String messageSuffix = "No CSS files will be analyzed.";
-
- String version;
- try {
- Process process = Runtime.getRuntime().exec(nodeExecutable + " -v");
- version = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8).trim();
- } catch (Exception e) {
- LOG.error("Failed to get Node.js version. " + messageSuffix, e);
- if (analysisWarnings != null) {
- analysisWarnings.addUnique(WARNING_PREFIX + "Node.js version could not be detected using command: " + nodeExecutable + " -v");
- }
- return false;
- }
-
- Pattern versionPattern = Pattern.compile("v?(\\d+)\\.\\d+\\.\\d+");
- Matcher versionMatcher = versionPattern.matcher(version);
- if (versionMatcher.matches()) {
- int major = Integer.parseInt(versionMatcher.group(1));
- if (major < MIN_NODE_VERSION) {
- String message = String.format("Only Node.js v%s or later is supported, got %s.", MIN_NODE_VERSION, version);
- LOG.error(message + ' ' + messageSuffix);
- if (analysisWarnings != null) {
- analysisWarnings.addUnique(WARNING_PREFIX + message);
- }
- return false;
- }
- } else {
- String message = String.format("Failed to parse Node.js version, got '%s'.", version);
- LOG.error(message + ' ' + messageSuffix);
- if (analysisWarnings != null) {
- analysisWarnings.addUnique(WARNING_PREFIX + message);
- }
- return false;
- }
-
- LOG.debug(String.format("Using Node.js %s", version));
- return true;
- }
-
private void createLinterConfig(File deployDestination) throws IOException {
String configPath = linterCommandProvider.configPath(deployDestination);
StylelintConfig config = cssRules.getConfig();
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/ExternalProcessStreamConsumer.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/ExternalProcessStreamConsumer.java
deleted file mode 100644
index ef843c4..0000000
--- a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/ExternalProcessStreamConsumer.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarCSS
- * Copyright (C) 2018-2019 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.css.plugin;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-class ExternalProcessStreamConsumer {
-
- private static final Logger LOG = Loggers.get(ExternalProcessStreamConsumer.class);
- private ExecutorService executorService;
-
- ExternalProcessStreamConsumer() {
- executorService = Executors.newCachedThreadPool(r -> {
- Thread thread = new Thread(r);
- thread.setName("nodejs-stream-consumer");
- thread.setDaemon(true);
- return thread;
- });
- }
-
- void consumeStream(InputStream inputStream, Consumer<String> consumer) {
- executorService.submit(() -> {
- try (BufferedReader errorReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
- errorReader.lines().forEach(consumer);
- } catch (IOException e) {
- LOG.error("Error while reading stream", e);
- }
- });
- }
-
- void await() throws InterruptedException {
- executorService.shutdown();
- if (!executorService.awaitTermination(5, TimeUnit.MINUTES)) {
- LOG.error("External process stream consumer timed out");
- }
- }
-
- void shutdownNow() {
- executorService.shutdownNow();
- }
-}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java
index 133e9a4..74a343c 100644
--- a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java
@@ -20,14 +20,14 @@
package org.sonar.css.plugin;
import java.io.File;
+import java.util.function.Consumer;
import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.config.Configuration;
+import org.sonarsource.nodejs.NodeCommand;
public interface LinterCommandProvider {
- String[] commandParts(File deployDestination, SensorContext context);
+ NodeCommand nodeCommand(File deployDestination, SensorContext context, Consumer<String> output, Consumer<String> error);
String configPath(File deployDestination);
- String nodeExecutable(Configuration configuration);
}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintCommandProvider.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintCommandProvider.java
index 0265c20..90d3ae8 100644
--- a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintCommandProvider.java
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintCommandProvider.java
@@ -21,38 +21,43 @@ package org.sonar.css.plugin;
import java.io.File;
import java.nio.file.Paths;
-import java.util.Optional;
+import java.util.function.Consumer;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
+import org.sonarsource.nodejs.NodeCommand;
+import org.sonarsource.nodejs.NodeCommandException;
@ScannerSide
public class StylelintCommandProvider implements LinterCommandProvider {
- private static final Logger LOG = Loggers.get(StylelintCommandProvider.class);
-
private static final String CONFIG_PATH = "css-bundle/stylelintconfig.json";
- private static final String NODE_EXECUTABLE_DEFAULT = "node";
-
- private String nodeExecutable = null;
@Override
- public String[] commandParts(File deployDestination, SensorContext context) {
+ public NodeCommand nodeCommand(File deployDestination, SensorContext context, Consumer<String> output, Consumer<String> error) {
String projectBaseDir = context.fileSystem().baseDir().getAbsolutePath();
String[] suffixes = context.config().getStringArray(CssPlugin.FILE_SUFFIXES_KEY);
String filesGlob = "**" + File.separator + "*{" + String.join(",", suffixes) + "}";
String filesToAnalyze = Paths.get(projectBaseDir, "TOREPLACE").toString();
filesToAnalyze = filesToAnalyze.replace("TOREPLACE", filesGlob);
- return new String[]{
- nodeExecutable(context.config()),
+ String[] args = {
new File(deployDestination, "css-bundle/node_modules/stylelint/bin/stylelint").getAbsolutePath(),
filesToAnalyze,
"--config", new File(deployDestination, CONFIG_PATH).getAbsolutePath(),
"-f", "json"
};
+
+ try {
+ return NodeCommand.builder()
+ .outputConsumer(output)
+ .errorConsumer(error)
+ .minNodeVersion(6)
+ .configuration(context.config())
+ .nodeJsArgs(args)
+ .build();
+ } catch (IllegalArgumentException e) {
+ throw new NodeCommandException(e.getMessage(), e);
+ }
}
@Override
@@ -60,27 +65,4 @@ public class StylelintCommandProvider implements LinterCommandProvider {
return new File(deployDestination, CONFIG_PATH).getAbsolutePath();
}
- @Override
- public String nodeExecutable(Configuration configuration) {
- if (nodeExecutable == null) {
- nodeExecutable = retrieveNodeExecutableFromConfig(configuration);
- }
-
- return nodeExecutable;
- }
-
- private static String retrieveNodeExecutableFromConfig(Configuration configuration) {
- Optional<String> nodeExecutableOptional = configuration.get(CssPlugin.NODE_EXECUTABLE);
- if (nodeExecutableOptional.isPresent()) {
- String nodeExecutable = nodeExecutableOptional.get();
- File file = new File(nodeExecutable);
- if (file.exists()) {
- return nodeExecutable;
- }
-
- LOG.warn("Provided node executable file does not exist: " + file + ". Fallback to using 'node' from path.");
- }
-
- return NODE_EXECUTABLE_DEFAULT;
- }
}
diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java
index b8c5cd4..792f065 100644
--- a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java
@@ -36,7 +36,7 @@ public class CssPluginTest {
Plugin.Context context = new Plugin.Context(runtime);
Plugin underTest = new CssPlugin();
underTest.define(context);
- assertThat(context.getExtensions()).hasSize(11);
+ assertThat(context.getExtensions()).hasSize(10);
}
@Test
@@ -45,7 +45,7 @@ public class CssPluginTest {
Plugin.Context context = new Plugin.Context(runtime);
Plugin underTest = new CssPlugin();
underTest.define(context);
- assertThat(context.getExtensions()).hasSize(12);
+ assertThat(context.getExtensions()).hasSize(11);
}
@Test
@@ -54,7 +54,7 @@ public class CssPluginTest {
Plugin.Context context = new Plugin.Context(runtime);
Plugin underTest = new CssPlugin();
underTest.define(context);
- assertThat(context.getExtensions()).hasSize(13);
+ assertThat(context.getExtensions()).hasSize(12);
}
@Test
@@ -63,6 +63,6 @@ public class CssPluginTest {
Plugin.Context context = new Plugin.Context(runtime);
Plugin underTest = new CssPlugin();
underTest.define(context);
- assertThat(context.getExtensions()).hasSize(12);
+ assertThat(context.getExtensions()).hasSize(11);
}
}
diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRuleSensorTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRuleSensorTest.java
index df3d034..f7f0d31 100644
--- a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRuleSensorTest.java
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRuleSensorTest.java
@@ -27,6 +27,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.awaitility.Awaitility;
import org.junit.Before;
@@ -42,16 +43,16 @@ import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
import org.sonar.api.batch.sensor.internal.SensorContextTester;
import org.sonar.api.batch.sensor.issue.Issue;
-import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.css.plugin.bundle.BundleHandler;
import org.sonar.css.plugin.bundle.CssBundleHandler;
+import org.sonarsource.nodejs.NodeCommand;
+import org.sonarsource.nodejs.NodeCommandException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.matches;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -107,37 +108,12 @@ public class CssRuleSensorTest {
@Test
public void test_invalid_node() {
- TestLinterCommandProvider commandProvider = getCommandProvider();
- commandProvider.nodeExecutable += " " + TestLinterCommandProvider.resourceScript("/executables/invalidNodeVersion.js");
+ InvalidCommandProvider commandProvider = new InvalidCommandProvider();
CssRuleSensor sensor = createCssRuleSensor(commandProvider);
sensor.execute(context);
assertThat(context.allIssues()).hasSize(0);
- assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Failed to parse Node.js version, got 'Invalid version'. No CSS files will be analyzed.");
- verifyZeroInteractions(analysisWarnings);
- }
-
- @Test
- public void test_no_node() {
- TestLinterCommandProvider commandProvider = getCommandProvider();
- commandProvider.nodeExecutable = TestLinterCommandProvider.resourceScript("/executables/invalidNodeVersion.js");
- CssRuleSensor sensor = createCssRuleSensor(commandProvider);
- sensor.execute(context);
-
- assertThat(context.allIssues()).hasSize(0);
- assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Failed to get Node.js version. No CSS files will be analyzed.");
- verifyZeroInteractions(analysisWarnings);
- }
-
- @Test
- public void test_old_node() {
- TestLinterCommandProvider commandProvider = getCommandProvider();
- commandProvider.nodeExecutable += " " + TestLinterCommandProvider.resourceScript("/executables/oldNodeVersion.js");
- CssRuleSensor sensor = createCssRuleSensor(commandProvider);
- sensor.execute(context);
-
- assertThat(context.allIssues()).hasSize(0);
- assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Only Node.js v6 or later is supported, got 3.2.1. No CSS files will be analyzed.");
+ assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Some problem happened. No CSS files will be analyzed.");
verifyZeroInteractions(analysisWarnings);
}
@@ -157,39 +133,14 @@ public class CssRuleSensorTest {
}
@Test
- public void test_invalid_node_with_analysisWarnings() {
- TestLinterCommandProvider commandProvider = getCommandProvider();
- commandProvider.nodeExecutable += " " + TestLinterCommandProvider.resourceScript("/executables/invalidNodeVersion.js");
- CssRuleSensor sensor = createCssRuleSensor(commandProvider, analysisWarnings);
- sensor.execute(context);
-
- assertThat(context.allIssues()).hasSize(0);
- assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Failed to parse Node.js version, got 'Invalid version'. No CSS files will be analyzed.");
- verify(analysisWarnings).addUnique(eq("CSS files were not analyzed. Failed to parse Node.js version, got 'Invalid version'."));
- }
-
- @Test
- public void test_no_node_with_analysisWarnings() {
- TestLinterCommandProvider commandProvider = getCommandProvider();
- commandProvider.nodeExecutable = TestLinterCommandProvider.resourceScript("/executables/invalidNodeVersion.js");
+ public void test_invalid_node_command_with_analysisWarnings() {
+ InvalidCommandProvider commandProvider = new InvalidCommandProvider();
CssRuleSensor sensor = createCssRuleSensor(commandProvider, analysisWarnings);
sensor.execute(context);
assertThat(context.allIssues()).hasSize(0);
- assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Failed to get Node.js version. No CSS files will be analyzed.");
- verify(analysisWarnings).addUnique(matches("CSS files were not analyzed. Node.js version could not be detected using command: .* -v"));
- }
-
- @Test
- public void test_old_node_with_analysisWarnings() {
- TestLinterCommandProvider commandProvider = getCommandProvider();
- commandProvider.nodeExecutable += " " + TestLinterCommandProvider.resourceScript("/executables/oldNodeVersion.js");
- CssRuleSensor sensor = createCssRuleSensor(commandProvider, analysisWarnings);
- sensor.execute(context);
-
- assertThat(context.allIssues()).hasSize(0);
- assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Only Node.js v6 or later is supported, got 3.2.1. No CSS files will be analyzed.");
- verify(analysisWarnings).addUnique(eq("CSS files were not analyzed. Only Node.js v6 or later is supported, got 3.2.1."));
+ assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Some problem happened. No CSS files will be analyzed.");
+ verify(analysisWarnings).addUnique(eq("CSS files were not analyzed. Some problem happened."));
}
@Test
@@ -267,11 +218,11 @@ public class CssRuleSensorTest {
return inputFile;
}
- private CssRuleSensor createCssRuleSensor(TestLinterCommandProvider commandProvider) {
+ private CssRuleSensor createCssRuleSensor(LinterCommandProvider commandProvider) {
return new CssRuleSensor(new TestBundleHandler(), checkFactory, commandProvider);
}
- private CssRuleSensor createCssRuleSensor(TestLinterCommandProvider commandProvider, @Nullable AnalysisWarningsWrapper analysisWarnings) {
+ private CssRuleSensor createCssRuleSensor(LinterCommandProvider commandProvider, @Nullable AnalysisWarningsWrapper analysisWarnings) {
return new CssRuleSensor(new TestBundleHandler(), checkFactory, commandProvider, analysisWarnings);
}
@@ -281,20 +232,8 @@ public class CssRuleSensorTest {
private static class TestLinterCommandProvider implements LinterCommandProvider {
- String nodeExecutable = findNodeExecutable();
-
private String[] elements;
- private static String findNodeExecutable() {
- try {
- String nodeFromMavenPlugin = "target/node/node";
- Runtime.getRuntime().exec(nodeFromMavenPlugin);
- return nodeFromMavenPlugin;
- } catch (IOException e) {
- return "node";
- }
- }
-
private static String resourceScript(String script) {
try {
return new File(TestLinterCommandProvider.class.getResource(script).toURI()).getAbsolutePath();
@@ -304,31 +243,45 @@ public class CssRuleSensorTest {
}
TestLinterCommandProvider nodeScript(String script, String args) {
- this.elements = new String[]{ nodeExecutable, resourceScript(script), args};
+ this.elements = new String[]{ resourceScript(script), args};
return this;
}
@Override
- public String[] commandParts(File deployDestination, SensorContext context) {
- return elements;
+ public NodeCommand nodeCommand(File deployDestination, SensorContext context, Consumer<String> output, Consumer<String> error) {
+ return NodeCommand.builder()
+ .outputConsumer(output)
+ .errorConsumer(error)
+ .minNodeVersion(6)
+ .configuration(context.config())
+ .nodeJsArgs(elements)
+ .build();
}
@Override
public String configPath(File deployDestination) {
return new File(deployDestination, "testconfig.json").getAbsolutePath();
}
+ }
+
+ private static class InvalidCommandProvider implements LinterCommandProvider {
+
+ @Override
+ public NodeCommand nodeCommand(File deployDestination, SensorContext context, Consumer<String> output, Consumer<String> error) {
+ throw new NodeCommandException("Some problem happened.");
+ }
@Override
- public String nodeExecutable(Configuration configuration) {
- return nodeExecutable;
+ public String configPath(File deployDestination) {
+ return new File(deployDestination, "testconfig.json").getAbsolutePath();
}
}
private static class TestBundleHandler implements BundleHandler {
-
@Override
public void deployBundle(File deployDestination) {
// do nothing
}
}
+
}
diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintCommandProviderTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintCommandProviderTest.java
index 1ae9a1d..9251fe0 100644
--- a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintCommandProviderTest.java
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintCommandProviderTest.java
@@ -20,13 +20,13 @@
package org.sonar.css.plugin;
import java.io.File;
+import java.util.function.Consumer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.sensor.internal.SensorContextTester;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
+import org.sonarsource.nodejs.NodeCommand;
import static org.assertj.core.api.Assertions.assertThat;
@@ -39,48 +39,22 @@ public class StylelintCommandProviderTest {
public final LogTester logTester = new LogTester();
@Test
- public void test() throws Exception {
+ public void test() {
StylelintCommandProvider stylelintCommandProvider = new StylelintCommandProvider();
File deployDestination = new File("deploy_destination");
File baseDir = new File("src/test/resources").getAbsoluteFile();
SensorContextTester context = SensorContextTester.create(baseDir);
context.settings().setProperty(CssPlugin.FILE_SUFFIXES_KEY, ".foo,.bar");
- assertThat(stylelintCommandProvider.commandParts(deployDestination, context)).containsExactly(
- "node",
+ Consumer<String> noop = a -> {};
+ NodeCommand nodeCommand = stylelintCommandProvider.nodeCommand(deployDestination, context, noop, noop);
+ assertThat(nodeCommand.toString()).endsWith(
+ String.join(" ",
new File(deployDestination, "css-bundle/node_modules/stylelint/bin/stylelint").getAbsolutePath(),
baseDir.getAbsolutePath() + File.separator + "**" + File.separator + "*{.foo,.bar}",
"--config",
new File(deployDestination, "css-bundle/stylelintconfig.json").getAbsolutePath(),
"-f",
- "json"
+ "json")
);
}
-
- @Test
- public void test_node_executable_wo_settings() throws Exception {
- StylelintCommandProvider stylelintCommandProvider = new StylelintCommandProvider();
- MapSettings settings = new MapSettings();
- assertThat(stylelintCommandProvider.nodeExecutable(settings.asConfig())).isEqualTo("node");
- assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
- }
-
- @Test
- public void test_node_executable_custom() throws Exception {
- StylelintCommandProvider stylelintCommandProvider = new StylelintCommandProvider();
- MapSettings settings = new MapSettings();
- File customNode = temporaryFolder.newFile("custom-node.exe");
- settings.setProperty(CssPlugin.NODE_EXECUTABLE, customNode.getAbsolutePath());
- assertThat(stylelintCommandProvider.nodeExecutable(settings.asConfig())).isEqualTo(customNode.getAbsolutePath());
- assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
- }
-
- @Test
- public void test_node_executable_custom_invalid() throws Exception {
- StylelintCommandProvider stylelintCommandProvider = new StylelintCommandProvider();
-
- MapSettings settings = new MapSettings();
- settings.setProperty(CssPlugin.NODE_EXECUTABLE, "mynode");
- assertThat(stylelintCommandProvider.nodeExecutable(settings.asConfig())).isEqualTo("node");
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Provided node executable file does not exist: mynode. Fallback to using 'node' from path.");
- }
}
diff --git a/sonar-css-plugin/src/test/resources/executables/invalidNodeVersion.js b/sonar-css-plugin/src/test/resources/executables/invalidNodeVersion.js
deleted file mode 100644
index 772b9f3..0000000
--- a/sonar-css-plugin/src/test/resources/executables/invalidNodeVersion.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log("Invalid version");