aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-css-plugin/src
diff options
context:
space:
mode:
authorElena Vilchik2018-06-14 17:40:32 +0200
committerGitHub2018-06-14 17:40:32 +0200
commit6383829aa3b6b25975da1fe7c618e3f611d8c6e1 (patch)
tree25752e58f8ef71a3a3db849a987dc24a1f54e0f1 /sonar-css-plugin/src
parentb3887099d35a9d8909c00f43ca194cc02ba0b16a (diff)
downloadsonar-css-6383829aa3b6b25975da1fe7c618e3f611d8c6e1.tar.bz2
Integrate stylelint inside plugin (#42)
Diffstat (limited to 'sonar-css-plugin/src')
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/BundleHandler.java28
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java5
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRuleSensor.java115
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRules.java70
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRulesDefinition.java46
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java28
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/SonarWayProfile.java8
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintExecution.java38
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/Zip.java52
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/bundle/CssBundleHandler.java55
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/bundle/package-info.java21
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/ColorNoInvalidHex.java31
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/CssRule.java26
-rw-r--r--sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/package-info.java21
-rw-r--r--sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.html29
-rw-r--r--sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.json16
-rw-r--r--sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json6
-rw-r--r--sonar-css-plugin/src/sonarcss-assembly.xml20
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssLanguageTest.java38
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java2
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRuleSensorTest.java125
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRulesDefinitionTest.java43
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/SonarWayProfileTest.java44
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintExecutionTest.java44
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/TestActiveRules.java114
-rw-r--r--sonar-css-plugin/src/test/java/org/sonar/css/plugin/bundle/CssBundleHandlerTest.java55
-rw-r--r--sonar-css-plugin/src/test/resources/.DS_Storebin0 -> 8196 bytes
-rw-r--r--sonar-css-plugin/src/test/resources/bundle/.DS_Storebin0 -> 6148 bytes
-rw-r--r--sonar-css-plugin/src/test/resources/bundle/test-bundle.zipbin0 -> 185 bytes
-rw-r--r--sonar-css-plugin/src/test/resources/executables/mockStylelint.js19
30 files changed, 1096 insertions, 3 deletions
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/BundleHandler.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/BundleHandler.java
new file mode 100644
index 0000000..79a7d5b
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/BundleHandler.java
@@ -0,0 +1,28 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.File;
+
+public interface BundleHandler {
+
+ void deployBundle(File deployDestination);
+
+}
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 65e6453..2835edb 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
@@ -22,6 +22,7 @@ package org.sonar.css.plugin;
import org.sonar.api.Plugin;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.resources.Qualifiers;
+import org.sonar.css.plugin.bundle.CssBundleHandler;
public class CssPlugin implements Plugin {
@@ -37,6 +38,10 @@ public class CssPlugin implements Plugin {
MetricSensor.class,
CssLanguage.class,
SonarWayProfile.class,
+ CssRulesDefinition.class,
+ CssBundleHandler.class,
+ CssRuleSensor.class,
+ StylelintExecution.class,
PropertyDefinition.builder(FILE_SUFFIXES_KEY)
.defaultValue(FILE_SUFFIXES_DEFVALUE)
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
new file mode 100644
index 0000000..8b6558b
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRuleSensor.java
@@ -0,0 +1,115 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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 com.google.gson.Gson;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import org.sonar.api.batch.fs.FileSystem;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.batch.sensor.Sensor;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewIssue;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+
+public class CssRuleSensor implements Sensor {
+
+ private final BundleHandler bundleHandler;
+ private final CssRules cssRules;
+ private final LinterCommandProvider linterCommandProvider;
+
+ public CssRuleSensor(BundleHandler bundleHandler, CheckFactory checkFactory, LinterCommandProvider linterCommandProvider) {
+ this.bundleHandler = bundleHandler;
+ this.linterCommandProvider = linterCommandProvider;
+ this.cssRules = new CssRules(checkFactory);
+ }
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor
+ .onlyOnLanguage(CssLanguage.KEY)
+ .name("SonarCSS Rules")
+ .onlyOnFileType(InputFile.Type.MAIN);
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ File deployDestination = context.fileSystem().workDir();
+ bundleHandler.deployBundle(deployDestination);
+
+ File projectBaseDir = context.fileSystem().baseDir();
+
+ String[] commandParts = linterCommandProvider.commandParts(deployDestination, projectBaseDir);
+ ProcessBuilder processBuilder = new ProcessBuilder(commandParts);
+
+ try {
+ Process process = processBuilder.start();
+
+ try (InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)) {
+ IssuesPerFile[] issues = new Gson().fromJson(inputStreamReader, IssuesPerFile[].class);
+ saveIssues(context, cssRules, issues);
+ }
+
+ } catch (IOException e) {
+ String command = String.join(" ", commandParts);
+ throw new IllegalStateException(String.format("Failed to run external process '%s'. Re-run analysis with debug option for more information.", command), e);
+ }
+ }
+
+ private static void saveIssues(SensorContext context, CssRules cssRules, IssuesPerFile[] issues) {
+ FileSystem fileSystem = context.fileSystem();
+
+ for (IssuesPerFile issuesPerFile : issues) {
+ InputFile inputFile = fileSystem.inputFile(fileSystem.predicates().hasAbsolutePath(issuesPerFile.source));
+
+ if (inputFile != null) {
+ for (Issue issue : issuesPerFile.warnings) {
+ NewIssue sonarIssue = context.newIssue();
+
+ NewIssueLocation location = sonarIssue.newLocation()
+ .on(inputFile)
+ .at(inputFile.selectLine(issue.line))
+ .message(issue.text);
+
+ sonarIssue
+ .at(location)
+ .forRule(cssRules.getSonarKey(issue.rule))
+ .save();
+ }
+ }
+ }
+ }
+
+ static class IssuesPerFile {
+ String source;
+ Issue[] warnings;
+ }
+
+ static class Issue {
+ int line;
+ String rule;
+ String text;
+ }
+
+}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRules.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRules.java
new file mode 100644
index 0000000..4ece37e
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRules.java
@@ -0,0 +1,70 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.batch.rule.Checks;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.css.plugin.rules.CssRule;
+import org.sonar.css.plugin.rules.ColorNoInvalidHex;
+
+public class CssRules {
+
+ private final Map<String, RuleKey> stylelintKeyToRuleKey;
+ private final StylelintConfig config = new StylelintConfig();
+
+ public CssRules(CheckFactory checkFactory) {
+ Checks<CssRule> checks = checkFactory.<CssRule>create(CssRulesDefinition.REPOSITORY_KEY).addAnnotatedChecks((Iterable) getRuleClasses());
+ Collection<CssRule> enabledRules = checks.all();
+ stylelintKeyToRuleKey = new HashMap<>();
+ for (CssRule rule : enabledRules) {
+ stylelintKeyToRuleKey.put(rule.stylelintKey(), checks.ruleKey(rule));
+ config.rules.put(rule.stylelintKey(), true);
+ }
+ }
+
+ public static List<Class> getRuleClasses() {
+ return Collections.unmodifiableList(Arrays.asList(
+ ColorNoInvalidHex.class
+ ));
+ }
+
+ public RuleKey getSonarKey(String stylelintKey) {
+ RuleKey ruleKey = stylelintKeyToRuleKey.get(stylelintKey);
+ if (ruleKey == null) {
+ throw new IllegalStateException("Unknown stylelint rule or rule not enabled " + stylelintKey);
+ }
+ return ruleKey;
+ }
+
+ public StylelintConfig getConfig() {
+ return config;
+ }
+
+ public static class StylelintConfig {
+ Map<String, Boolean> rules = new HashMap<>();
+ }
+}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRulesDefinition.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRulesDefinition.java
new file mode 100644
index 0000000..196252f
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssRulesDefinition.java
@@ -0,0 +1,46 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.util.Collections;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.css.plugin.rules.ColorNoInvalidHex;
+import org.sonarsource.analyzer.commons.RuleMetadataLoader;
+
+import static org.sonar.css.plugin.SonarWayProfile.PROFILE_PATH;
+
+public class CssRulesDefinition implements RulesDefinition {
+
+ public static final String REPOSITORY_KEY = "css";
+ public static final String RULE_REPOSITORY_NAME = "SonarAnalyzer";
+
+ public static final String RESOURCE_FOLDER = "org/sonar/l10n/css/rules/css";
+
+ @Override
+ public void define(Context context) {
+ NewRepository repository = context
+ .createRepository(REPOSITORY_KEY, CssLanguage.KEY)
+ .setName(RULE_REPOSITORY_NAME);
+
+ RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_FOLDER, PROFILE_PATH);
+ ruleMetadataLoader.addRulesByAnnotatedClass(repository, Collections.singletonList(ColorNoInvalidHex.class));
+ repository.done();
+ }
+}
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
new file mode 100644
index 0000000..6f06c84
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/LinterCommandProvider.java
@@ -0,0 +1,28 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.File;
+
+public interface LinterCommandProvider {
+
+ String[] commandParts(File deployDestination, File projectBaseDir);
+
+}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/SonarWayProfile.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/SonarWayProfile.java
index a54de22..01f6d83 100644
--- a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/SonarWayProfile.java
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/SonarWayProfile.java
@@ -20,16 +20,20 @@
package org.sonar.css.plugin;
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition;
+import org.sonarsource.analyzer.commons.BuiltInQualityProfileJsonLoader;
+
+import static org.sonar.css.plugin.CssRulesDefinition.REPOSITORY_KEY;
+import static org.sonar.css.plugin.CssRulesDefinition.RESOURCE_FOLDER;
public class SonarWayProfile implements BuiltInQualityProfilesDefinition {
public static final String PROFILE_NAME = "Sonar way";
-// private static final String PROFILE_PATH = "org/sonar/l10n/css/rules/css/Sonar_way_profile.json";
+ public static final String PROFILE_PATH = RESOURCE_FOLDER + "/Sonar_way_profile.json";
@Override
public void define(Context context) {
-
NewBuiltInQualityProfile profile = context.createBuiltInQualityProfile(PROFILE_NAME, CssLanguage.KEY);
+ BuiltInQualityProfileJsonLoader.load(profile, REPOSITORY_KEY, PROFILE_PATH);
profile.done();
}
}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintExecution.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintExecution.java
new file mode 100644
index 0000000..c88a0ac
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/StylelintExecution.java
@@ -0,0 +1,38 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.File;
+import org.sonar.api.batch.ScannerSide;
+
+@ScannerSide
+public class StylelintExecution implements LinterCommandProvider {
+
+ @Override
+ public String[] commandParts(File deployDestination, File projectBaseDir) {
+ return new String[]{
+ "node",
+ new File(deployDestination, "css-bundle/node_modules/stylelint/bin/stylelint").getAbsolutePath(),
+ projectBaseDir.getAbsolutePath(),
+ "--config", new File(deployDestination, "css-bundle/stylelintconfig.json").getAbsolutePath(),
+ "-f", "json"
+ };
+ }
+}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/Zip.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/Zip.java
new file mode 100644
index 0000000..62df45e
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/Zip.java
@@ -0,0 +1,52 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import org.apache.commons.io.FileUtils;
+
+public class Zip {
+
+ private Zip() {
+ // utility class
+ }
+
+ public static void extract(InputStream bundle, File destination) throws IOException {
+ ZipInputStream zip = new ZipInputStream(bundle);
+ ZipEntry entry = zip.getNextEntry();
+ if (entry == null) {
+ throw new IllegalStateException("At least one entry expected.");
+ }
+ while (entry != null) {
+ File entryDestination = new File(destination, entry.getName());
+ if (entry.isDirectory()) {
+ entryDestination.mkdirs();
+ } else {
+ FileUtils.copyToFile(zip, entryDestination);
+ }
+ zip.closeEntry();
+ entry = zip.getNextEntry();
+ }
+ }
+}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/bundle/CssBundleHandler.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/bundle/CssBundleHandler.java
new file mode 100644
index 0000000..acf9245
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/bundle/CssBundleHandler.java
@@ -0,0 +1,55 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.bundle;
+
+import java.io.File;
+import java.io.InputStream;
+import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.css.plugin.BundleHandler;
+import org.sonar.css.plugin.Zip;
+
+@ScannerSide
+public class CssBundleHandler implements BundleHandler {
+
+ private static final String BUNDLE_LOCATION = "/css-bundle.zip";
+ private static final Logger LOG = Loggers.get(CssBundleHandler.class);
+ String bundleLocation = BUNDLE_LOCATION;
+
+ /**
+ * Extracting "css-bundle.zip" (containing stylelint)
+ * to deployDestination (".sonar" directory of the analyzed project).
+ */
+ @Override
+ public void deployBundle(File deployDestination) {
+ InputStream bundle = getClass().getResourceAsStream(bundleLocation);
+ if (bundle == null) {
+ throw new IllegalStateException("CSS bundle not found at " + bundleLocation);
+ }
+ try {
+ LOG.debug("Deploying bundle to {}", deployDestination.getAbsolutePath());
+ Zip.extract(bundle, deployDestination);
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to deploy CSS bundle (with classpath '" + bundleLocation + "')", e);
+ }
+ }
+
+}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/bundle/package-info.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/bundle/package-info.java
new file mode 100644
index 0000000..003d535
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/bundle/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.
+ */
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.css.plugin.bundle;
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/ColorNoInvalidHex.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/ColorNoInvalidHex.java
new file mode 100644
index 0000000..b976abb
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/ColorNoInvalidHex.java
@@ -0,0 +1,31 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.rules;
+
+import org.sonar.check.Rule;
+
+@Rule(key = "S4647")
+public class ColorNoInvalidHex implements CssRule {
+
+ @Override
+ public String stylelintKey() {
+ return "color-no-invalid-hex";
+ }
+}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/CssRule.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/CssRule.java
new file mode 100644
index 0000000..237228b
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/CssRule.java
@@ -0,0 +1,26 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.rules;
+
+public interface CssRule {
+
+ String stylelintKey();
+
+}
diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/package-info.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/package-info.java
new file mode 100644
index 0000000..2c279a3
--- /dev/null
+++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/rules/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.
+ */
+@javax.annotation.ParametersAreNonnullByDefault
+package org.sonar.css.plugin.rules;
diff --git a/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.html b/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.html
new file mode 100644
index 0000000..10aa560
--- /dev/null
+++ b/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.html
@@ -0,0 +1,29 @@
+<p>An invalid color definition will by default be interpreted as black, which is likely to have unintended impacts on the expected look and feel of
+the website.</p>
+<p>This rule raises an issue when a color definition <code>color</code>, <code>background-color</code> is not valid. The color definition is
+considered valid when it is made of hexadecimal characters:</p>
+<p>- longhand: 6 or 8 characters (when alpha is defined)</p>
+<p>- shorthand variant: 3 or 4 characters (when alpha is defined)</p>
+<h2>Noncompliant Code Example</h2>
+<pre>
+a {
+ color: #3c; // Noncompliant: shorthand should be made of 3 characters
+}
+div {
+ background-color: #3cb371a; // Noncompliant: alpha should have 2 characters
+}
+</pre>
+<h2>Compliant Solution</h2>
+<pre>
+a {
+ color: #3cc;
+}
+div {
+ background-color: #3cb371ac;
+}
+</pre>
+<h2>See</h2>
+<ul>
+ <li> <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value">Mozilla Web Technology for Developers</a> - CSS Color </li>
+</ul>
+
diff --git a/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.json b/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.json
new file mode 100644
index 0000000..afb0676
--- /dev/null
+++ b/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/S4647.json
@@ -0,0 +1,16 @@
+{
+ "title": "Color definitions should be valid",
+ "type": "BUG",
+ "status": "ready",
+ "remediation": {
+ "func": "Constant\/Issue",
+ "constantCost": "1min"
+ },
+ "tags": [
+
+ ],
+ "defaultSeverity": "Blocker",
+ "ruleSpecification": "RSPEC-4647",
+ "sqKey": "S4647",
+ "scope": "All"
+}
diff --git a/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json b/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json
new file mode 100644
index 0000000..ba5ce46
--- /dev/null
+++ b/sonar-css-plugin/src/main/resources/org/sonar/l10n/css/rules/css/Sonar_way_profile.json
@@ -0,0 +1,6 @@
+{
+ "name": "Sonar way",
+ "ruleKeys": [
+ "S4647"
+ ]
+}
diff --git a/sonar-css-plugin/src/sonarcss-assembly.xml b/sonar-css-plugin/src/sonarcss-assembly.xml
new file mode 100644
index 0000000..dcbab0f
--- /dev/null
+++ b/sonar-css-plugin/src/sonarcss-assembly.xml
@@ -0,0 +1,20 @@
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
+ <id>sonarcss-assembly</id>
+ <formats>
+ <format>zip</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>css-bundle</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ <excludes>
+ <exclude>package-lock.json</exclude>
+ </excludes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssLanguageTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssLanguageTest.java
new file mode 100644
index 0000000..cf5c65a
--- /dev/null
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssLanguageTest.java
@@ -0,0 +1,38 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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 org.junit.Test;
+import org.sonar.api.config.internal.MapSettings;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CssLanguageTest {
+
+ @Test
+ public void test() throws Exception {
+ MapSettings settings = new MapSettings();
+ settings.setProperty(CssPlugin.FILE_SUFFIXES_KEY, CssPlugin.FILE_SUFFIXES_DEFVALUE);
+ CssLanguage language = new CssLanguage(settings.asConfig());
+ assertThat(language.getKey()).isEqualTo("css");
+ assertThat(language.getName()).isEqualTo("CSS");
+ assertThat(language.getFileSuffixes()).containsOnly(".css", ".less", ".scss");
+ }
+}
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 33bd4dd..1cbade9 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,6 +36,6 @@ public class CssPluginTest {
Plugin.Context context = new Plugin.Context(runtime);
Plugin underTest = new CssPlugin();
underTest.define(context);
- assertThat(context.getExtensions()).hasSize(4);
+ assertThat(context.getExtensions()).hasSize(8);
}
}
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
new file mode 100644
index 0000000..a4d5921
--- /dev/null
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRuleSensorTest.java
@@ -0,0 +1,125 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.batch.fs.InputFile.Type;
+import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.batch.rule.CheckFactory;
+import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
+import org.sonar.api.batch.sensor.internal.SensorContextTester;
+import org.sonar.css.plugin.bundle.CssBundleHandler;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CssRuleSensorTest {
+
+ 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();
+
+ @Test
+ public void test_descriptor() throws Exception {
+ CssRuleSensor sensor = new CssRuleSensor(new CssBundleHandler(), checkFactory, new StylelintExecution());
+ DefaultSensorDescriptor sensorDescriptor = new DefaultSensorDescriptor();
+ sensor.describe(sensorDescriptor);
+ assertThat(sensorDescriptor.name()).isEqualTo("SonarCSS Rules");
+ assertThat(sensorDescriptor.languages()).containsOnly("css");
+ assertThat(sensorDescriptor.type()).isEqualTo(Type.MAIN);
+ }
+
+ @Test
+ public void test_execute() throws Exception {
+ 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);
+ sensor.execute(context);
+
+ assertThat(context.allIssues()).hasSize(1);
+ }
+
+ private static DefaultInputFile createInputFile(SensorContextTester sensorContext, String content, String relativePath) {
+ DefaultInputFile inputFile = new TestInputFileBuilder("moduleKey", relativePath)
+ .setModuleBaseDir(sensorContext.fileSystem().baseDirPath())
+ .setType(Type.MAIN)
+ .setLanguage(CssLanguage.KEY)
+ .setCharset(StandardCharsets.UTF_8)
+ .setContents(content)
+ .build();
+
+ sensorContext.fileSystem().add(inputFile);
+ return inputFile;
+ }
+
+ private static class TestLinterCommandProvider implements LinterCommandProvider {
+
+ private static 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();
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ static TestLinterCommandProvider nodeScript(String script, String args) {
+ TestLinterCommandProvider testRulesExecution = new TestLinterCommandProvider();
+ testRulesExecution.elements = new String[]{ nodeExecutable, resourceScript(script), args};
+ return testRulesExecution;
+ }
+
+ @Override
+ public String[] commandParts(File deployDestination, File projectBaseDir) {
+ return elements;
+ }
+ }
+
+ 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/CssRulesDefinitionTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRulesDefinitionTest.java
new file mode 100644
index 0000000..7dffb35
--- /dev/null
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssRulesDefinitionTest.java
@@ -0,0 +1,43 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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 org.junit.Test;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CssRulesDefinitionTest {
+
+ @Test
+ public void test() {
+ CssRulesDefinition rulesDefinition = new CssRulesDefinition();
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ rulesDefinition.define(context);
+ RulesDefinition.Repository repository = context.repository("css");
+
+ assertThat(context.repositories()).hasSize(1);
+
+ assertThat(repository.name()).isEqualTo("SonarAnalyzer");
+ assertThat(repository.language()).isEqualTo("css");
+ assertThat(repository.isExternal()).isEqualTo(false);
+ assertThat(repository.rules()).hasSize(CssRules.getRuleClasses().size());
+ }
+}
diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/SonarWayProfileTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/SonarWayProfileTest.java
new file mode 100644
index 0000000..eba68f5
--- /dev/null
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/SonarWayProfileTest.java
@@ -0,0 +1,44 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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 org.junit.Test;
+import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInQualityProfile;
+import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.Context;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SonarWayProfileTest {
+
+ @Test
+ public void should_create_sonar_way_profile() {
+ SonarWayProfile definition = new SonarWayProfile();
+ Context context = new Context();
+ definition.define(context);
+
+ BuiltInQualityProfile profile = context.profile("css", SonarWayProfile.PROFILE_NAME);
+
+ assertThat(profile.language()).isEqualTo(CssLanguage.KEY);
+ assertThat(profile.name()).isEqualTo(SonarWayProfile.PROFILE_NAME);
+ assertThat(profile.rules()).extracting("repoKey").containsOnly(CssRulesDefinition.REPOSITORY_KEY);
+ assertThat(profile.rules()).extracting("ruleKey").contains("S4647");
+ }
+
+}
diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintExecutionTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintExecutionTest.java
new file mode 100644
index 0000000..4ca78db
--- /dev/null
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/StylelintExecutionTest.java
@@ -0,0 +1,44 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.File;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class StylelintExecutionTest {
+
+ @Test
+ public void test() throws Exception {
+ StylelintExecution stylelintExecution = new StylelintExecution();
+ File deployDestination = new File("deploy_destination");
+ File baseDir = new File("base_dir");
+ assertThat(stylelintExecution.commandParts(deployDestination, baseDir)).containsExactly(
+ "node",
+ new File(deployDestination, "css-bundle/node_modules/stylelint/bin/stylelint").getAbsolutePath(),
+ baseDir.getAbsolutePath(),
+ "--config",
+ new File(deployDestination, "css-bundle/stylelintconfig.json").getAbsolutePath(),
+ "-f",
+ "json"
+ );
+ }
+}
diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/TestActiveRules.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/TestActiveRules.java
new file mode 100644
index 0000000..76ae3d7
--- /dev/null
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/TestActiveRules.java
@@ -0,0 +1,114 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.CheckForNull;
+import org.sonar.api.batch.rule.ActiveRule;
+import org.sonar.api.batch.rule.ActiveRules;
+import org.sonar.api.rule.RuleKey;
+
+public class TestActiveRules implements ActiveRules {
+
+ private final List<ActiveRule> activeRules;
+
+ public TestActiveRules(String... activeRules) {
+ this.activeRules = Arrays.stream(activeRules).map(TestActiveRule::new).collect(Collectors.toList());
+ }
+
+ @CheckForNull
+ @Override
+ public ActiveRule find(RuleKey ruleKey) {
+ return null;
+ }
+
+ @Override
+ public Collection<ActiveRule> findAll() {
+ return activeRules;
+ }
+
+ @Override
+ public Collection<ActiveRule> findByRepository(String repository) {
+ return activeRules;
+ }
+
+ @Override
+ public Collection<ActiveRule> findByLanguage(String language) {
+ return activeRules;
+ }
+
+ @CheckForNull
+ @Override
+ public ActiveRule findByInternalKey(String repository, String internalKey) {
+ return null;
+ }
+
+ class TestActiveRule implements ActiveRule {
+
+ final RuleKey ruleKey;
+
+ public TestActiveRule(String key) {
+ ruleKey = RuleKey.of(CssRulesDefinition.REPOSITORY_KEY, key);
+ }
+
+ @Override
+ public RuleKey ruleKey() {
+ return ruleKey;
+ }
+
+ @Override
+ public String severity() {
+ return null;
+ }
+
+ @Override
+ public String language() {
+ return null;
+ }
+
+ @CheckForNull
+ @Override
+ public String param(String key) {
+ return null;
+ }
+
+ @Override
+ public Map<String, String> params() {
+ return Collections.emptyMap();
+ }
+
+ @CheckForNull
+ @Override
+ public String internalKey() {
+ return null;
+ }
+
+ @CheckForNull
+ @Override
+ public String templateRuleKey() {
+ return null;
+ }
+ }
+}
diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/bundle/CssBundleHandlerTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/bundle/CssBundleHandlerTest.java
new file mode 100644
index 0000000..b55d050
--- /dev/null
+++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/bundle/CssBundleHandlerTest.java
@@ -0,0 +1,55 @@
+/*
+ * SonarCSS
+ * Copyright (C) 2018-2018 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.bundle;
+
+import java.io.File;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CssBundleHandlerTest {
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private File DEPLOY_DESTINATION;
+
+ @Before
+ public void setUp() throws Exception {
+ DEPLOY_DESTINATION = temporaryFolder.newFolder("deployDestination");
+ }
+
+ @Test
+ public void test() throws Exception {
+ CssBundleHandler bundleHandler = new CssBundleHandler();
+ bundleHandler.bundleLocation = "/bundle/test-bundle.zip";
+ bundleHandler.deployBundle(DEPLOY_DESTINATION);
+
+ assertThat(new File(DEPLOY_DESTINATION, "test-bundle.js").exists()).isTrue();
+ }
+
+}
diff --git a/sonar-css-plugin/src/test/resources/.DS_Store b/sonar-css-plugin/src/test/resources/.DS_Store
new file mode 100644
index 0000000..63066fe
--- /dev/null
+++ b/sonar-css-plugin/src/test/resources/.DS_Store
Binary files differ
diff --git a/sonar-css-plugin/src/test/resources/bundle/.DS_Store b/sonar-css-plugin/src/test/resources/bundle/.DS_Store
new file mode 100644
index 0000000..5008ddf
--- /dev/null
+++ b/sonar-css-plugin/src/test/resources/bundle/.DS_Store
Binary files differ
diff --git a/sonar-css-plugin/src/test/resources/bundle/test-bundle.zip b/sonar-css-plugin/src/test/resources/bundle/test-bundle.zip
new file mode 100644
index 0000000..446e89f
--- /dev/null
+++ b/sonar-css-plugin/src/test/resources/bundle/test-bundle.zip
Binary files differ
diff --git a/sonar-css-plugin/src/test/resources/executables/mockStylelint.js b/sonar-css-plugin/src/test/resources/executables/mockStylelint.js
new file mode 100644
index 0000000..e8c1667
--- /dev/null
+++ b/sonar-css-plugin/src/test/resources/executables/mockStylelint.js
@@ -0,0 +1,19 @@
+#!/usr/bin/env node
+var testFile = process.argv[2];
+
+var result = [
+ {
+ source: testFile,
+
+ warnings: [
+ {
+ text: "some message",
+ line: 2,
+ rule: "color-no-invalid-hex"
+ }
+ ]
+ }
+];
+
+var json = JSON.stringify(result);
+console.log(json);