aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElena Vilchik2018-06-25 15:20:12 +0200
committerGitHub2018-06-25 15:20:12 +0200
commit7a31cb18a718601f31766cf8e02c6ad85f3916f0 (patch)
tree3f8c71f48b8e23c1af06a53ab405e5bb23357900
parentb45e6c9923f9ab8a27a81430dfea81d5302922d3 (diff)
downloadsonar-css-7a31cb18a718601f31766cf8e02c6ad85f3916f0.tar.bz2
Not fail analysis if Node is not available (#73)
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRuleSensor.java43
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java3
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintCommandProvider.java9
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRuleSensorTest.java87
-rw-r--r--sonar-css-plugin/src/test/resources/executables/invalidNodeVersion.js1
-rw-r--r--sonar-css-plugin/src/test/resources/executables/oldNodeVersion.js1
6 files changed, 125 insertions, 19 deletions
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 c669b30..d13038e 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
@@ -30,6 +30,7 @@ import java.nio.file.Paths;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+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;
@@ -39,6 +40,8 @@ import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.issue.NewIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
import org.sonar.css.plugin.CssRules.StylelintConfig;
import org.sonar.css.plugin.StylelintReport.Issue;
import org.sonar.css.plugin.StylelintReport.IssuesPerFile;
@@ -46,6 +49,9 @@ import org.sonar.css.plugin.bundle.BundleHandler;
public class CssRuleSensor implements Sensor {
+ private static final Logger LOG = Loggers.get(CssRuleSensor.class);
+ private static final int MIN_NODE_VERSION = 6;
+
private final BundleHandler bundleHandler;
private final CssRules cssRules;
private final LinterCommandProvider linterCommandProvider;
@@ -65,6 +71,10 @@ public class CssRuleSensor implements Sensor {
@Override
public void execute(SensorContext context) {
+ if (!checkCompatibleNodeVersion(context)) {
+ return;
+ }
+
File deployDestination = context.fileSystem().workDir();
bundleHandler.deployBundle(deployDestination);
@@ -89,6 +99,39 @@ public class CssRuleSensor implements Sensor {
}
}
+ 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);
+ 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. %s", MIN_NODE_VERSION, version, messageSuffix);
+ LOG.error(message);
+ return false;
+ }
+ } else {
+ String message = String.format("Failed to parse Node.js version, got '%s'. %s", version, messageSuffix);
+ LOG.error(message);
+ return false;
+ }
+
+ LOG.debug(String.format("Using Node.js %s", version));
+ return true;
+ }
+
private void createConfig(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/LinterCommandProvider.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java
index 3ca334a..761b88d 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
@@ -21,10 +21,13 @@ package org.sonar.css.plugin;
import java.io.File;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.config.Configuration;
public interface LinterCommandProvider {
String[] commandParts(File deployDestination, SensorContext context);
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 d97293d..b2f50b5 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
@@ -23,11 +23,13 @@ import java.io.File;
import java.nio.file.Paths;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.config.Configuration;
@ScannerSide
public class StylelintCommandProvider implements LinterCommandProvider {
private static final String CONFIG_PATH = "css-bundle/stylelintconfig.json";
+ private static final String NODE_EXECUTABLE = "node";
@Override
public String[] commandParts(File deployDestination, SensorContext context) {
@@ -38,7 +40,7 @@ public class StylelintCommandProvider implements LinterCommandProvider {
filesToAnalyze = filesToAnalyze.replace("TOREPLACE", filesGlob);
return new String[]{
- "node",
+ nodeExecutable(context.config()),
new File(deployDestination, "css-bundle/node_modules/stylelint/bin/stylelint").getAbsolutePath(),
filesToAnalyze,
"--config", new File(deployDestination, CONFIG_PATH).getAbsolutePath(),
@@ -50,4 +52,9 @@ public class StylelintCommandProvider implements LinterCommandProvider {
public String configPath(File deployDestination) {
return new File(deployDestination, CONFIG_PATH).getAbsolutePath();
}
+
+ @Override
+ public String nodeExecutable(Configuration configuration) {
+ return NODE_EXECUTABLE;
+ }
}
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 06295d7..030a987 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
@@ -26,6 +26,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -38,6 +39,9 @@ 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;
@@ -46,13 +50,25 @@ import static org.assertj.core.api.Assertions.assertThat;
public class CssRuleSensorTest {
@Rule
+ public final LogTester logTester = new LogTester();
+
+ @Rule
+ public TemporaryFolder tmpDir = new TemporaryFolder();
+
+ @Rule
public ExpectedException thrown= ExpectedException.none();
private static CheckFactory checkFactory = new CheckFactory(new TestActiveRules("S4647"));
- private File BASE_DIR = new File("src/test/resources").getAbsoluteFile();
- @Rule
- public TemporaryFolder tmpDir = new TemporaryFolder();
+ private static final File BASE_DIR = new File("src/test/resources").getAbsoluteFile();
+
+ private SensorContextTester context = SensorContextTester.create(BASE_DIR);
+ private DefaultInputFile inputFile = createInputFile(context, "some css content\n on 2 lines", "dir/file.css");
+
+ @Before
+ public void setUp() throws Exception {
+ context.fileSystem().setWorkDir(tmpDir.getRoot().toPath());
+ }
@Test
public void test_descriptor() {
@@ -65,11 +81,8 @@ public class CssRuleSensorTest {
@Test
public void test_execute() throws IOException {
- SensorContextTester context = SensorContextTester.create(BASE_DIR);
- context.fileSystem().setWorkDir(tmpDir.getRoot().toPath());
- DefaultInputFile inputFile = createInputFile(context, "some css content\n on 2 lines", "dir/file.css");
- TestLinterCommandProvider rulesExecution = TestLinterCommandProvider.nodeScript("/executables/mockStylelint.js", inputFile.absolutePath());
- CssRuleSensor sensor = new CssRuleSensor(new TestBundleHandler(), checkFactory, rulesExecution);
+ TestLinterCommandProvider commandProvider = getCommandProvider();
+ CssRuleSensor sensor = new CssRuleSensor(new TestBundleHandler(), checkFactory, commandProvider);
sensor.execute(context);
assertThat(context.allIssues()).hasSize(1);
@@ -81,15 +94,45 @@ public class CssRuleSensorTest {
}
@Test
+ public void test_invalid_node() throws IOException {
+ TestLinterCommandProvider commandProvider = getCommandProvider();
+ commandProvider.nodeExecutable += " " + TestLinterCommandProvider.resourceScript("/executables/invalidNodeVersion.js");
+ CssRuleSensor sensor = new CssRuleSensor(new TestBundleHandler(), checkFactory, 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.");
+ }
+
+ @Test
+ public void test_no_node() throws IOException {
+ TestLinterCommandProvider commandProvider = getCommandProvider();
+ commandProvider.nodeExecutable = TestLinterCommandProvider.resourceScript("/executables/invalidNodeVersion.js");
+ CssRuleSensor sensor = new CssRuleSensor(new TestBundleHandler(), checkFactory, 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.");
+ }
+
+ @Test
+ public void test_old_node() throws IOException {
+ TestLinterCommandProvider commandProvider = getCommandProvider();
+ commandProvider.nodeExecutable += " " + TestLinterCommandProvider.resourceScript("/executables/oldNodeVersion.js");
+ CssRuleSensor sensor = new CssRuleSensor(new TestBundleHandler(), checkFactory, 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.");
+ }
+
+ @Test
public void test_error() throws IOException {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Failed to parse json result of external process execution");
- SensorContextTester context = SensorContextTester.create(BASE_DIR);
- context.fileSystem().setWorkDir(tmpDir.getRoot().toPath());
- DefaultInputFile inputFile = createInputFile(context, "some css content\n on 2 lines", "dir/file.css");
- TestLinterCommandProvider rulesExecution = TestLinterCommandProvider.nodeScript("/executables/mockError.js", inputFile.absolutePath());
- CssRuleSensor sensor = new CssRuleSensor(new TestBundleHandler(), checkFactory, rulesExecution);
+ TestLinterCommandProvider commandProvider = new TestLinterCommandProvider().nodeScript("/executables/mockError.js", inputFile.absolutePath());
+ CssRuleSensor sensor = new CssRuleSensor(new TestBundleHandler(), checkFactory, commandProvider);
sensor.execute(context);
}
@@ -106,9 +149,13 @@ public class CssRuleSensorTest {
return inputFile;
}
+ private TestLinterCommandProvider getCommandProvider() {
+ return new TestLinterCommandProvider().nodeScript("/executables/mockStylelint.js", inputFile.absolutePath());
+ }
+
private static class TestLinterCommandProvider implements LinterCommandProvider {
- private static String nodeExecutable = findNodeExecutable();
+ String nodeExecutable = findNodeExecutable();
private String[] elements;
@@ -130,10 +177,9 @@ public class CssRuleSensorTest {
}
}
- static TestLinterCommandProvider nodeScript(String script, String args) {
- TestLinterCommandProvider testRulesExecution = new TestLinterCommandProvider();
- testRulesExecution.elements = new String[]{ nodeExecutable, resourceScript(script), args};
- return testRulesExecution;
+ TestLinterCommandProvider nodeScript(String script, String args) {
+ this.elements = new String[]{ nodeExecutable, resourceScript(script), args};
+ return this;
}
@Override
@@ -145,6 +191,11 @@ public class CssRuleSensorTest {
public String configPath(File deployDestination) {
return new File(deployDestination, "testconfig.json").getAbsolutePath();
}
+
+ @Override
+ public String nodeExecutable(Configuration configuration) {
+ return nodeExecutable;
+ }
}
private static class TestBundleHandler implements BundleHandler {
diff --git a/sonar-css-plugin/src/test/resources/executables/invalidNodeVersion.js b/sonar-css-plugin/src/test/resources/executables/invalidNodeVersion.js
new file mode 100644
index 0000000..772b9f3
--- /dev/null
+++ b/sonar-css-plugin/src/test/resources/executables/invalidNodeVersion.js
@@ -0,0 +1 @@
+console.log("Invalid version");
diff --git a/sonar-css-plugin/src/test/resources/executables/oldNodeVersion.js b/sonar-css-plugin/src/test/resources/executables/oldNodeVersion.js
new file mode 100644
index 0000000..817b98a
--- /dev/null
+++ b/sonar-css-plugin/src/test/resources/executables/oldNodeVersion.js
@@ -0,0 +1 @@
+console.log("3.2.1");