Skip to content
This repository has been archived by the owner on Jul 8, 2019. It is now read-only.

Commit

Permalink
Merge branch 'drywolf-master' - PR #31
Browse files Browse the repository at this point in the history
  • Loading branch information
Pablissimo committed Jul 23, 2016
2 parents 5097151 + edec577 commit dd89fec
Show file tree
Hide file tree
Showing 12 changed files with 1,161 additions and 344 deletions.
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ The plugin has so far *only been tested on Windows* and it'll be no surprise if
<tr><th>Key</th><th></th><th>Description</th></thead>
<tbody>
<tr><td>sonar.ts.tslintpath</td><td><b>Mandatory</b></td><td>Path to the installed copy of TsLint to use</td></tr>
<tr><td>sonar.ts.tslint.customrules</td><td><b>Optional</b></td><td>Configuration to map custom TSLint rules to SonarQube rules & settings</td></tr>
<tr><td>sonar.ts.ruleconfigs</td><td><b>Optional</b></td><td>A list of configurations to map custom TSLint rules to dedicated SonarQube rules & settings - see TsLint Custom Rules section below</td></tr>
</tbody>
</table>

Expand All @@ -92,14 +94,36 @@ The plugin has so far *only been tested on Windows* and it'll be no surprise if
</tbody>
</table>

## TsLint Custom Rules

To present custom TSLint rules in SonarQube analysis, you can provide a configuration that maps the TsLint rules from your `sonar.ts.tslintrulesdir`
directory to dedicated Sonar rules for analysis.
The configuration for a TSLint Sonar rule consists of a line declaring the TSLint rule id, a boolean switch to enable or disable the rule if needed
and some attached properties that are used by Sonar for analysis and reporting.

For example taking the `export-name` rule from the [tslint-microsoft-contrib](https://github.com/Microsoft/tslint-microsoft-contrib) package,
a configuration for that rule in SonarTsPlugin could look as follows:

export-name=true
export-name.name=The name of the exported module must match the filename of the source file.
export-name.severity=MAJOR
export-name.description=This is case-sensitive but ignores file extension. Since version 1.0, this rule takes a list of regular expressions as a parameter. Any export name matching that regular expression will be ignored.
export-name.debtFunc=LINEAR_OFFSET
export-name.debtScalar=15min
export-name.debtOffset=1h
export-name.debtType=HARDWARE_RELATED_PORTABILITY

* for documentation about the `technical debt` parameters look [here](http://docs.sonarqube.org/display/PLUG/Rule+Remediation+Costs) and [here](http://javadocs.sonarsource.org/5.2/apidocs/org/sonar/api/server/debt/DebtRemediationFunction.html)
* for possible values for `debtType` go [here](http://javadocs.sonarsource.org/5.2/apidocs/org/sonar/api/server/rule/RulesDefinition.SubCharacteristics.html)

##Licence
MIT

##Contributors
Thanks to the following for contributions to the plugin:
* [Alex Krauss](https://github.com/alexkrauss) and [Manuel Huber](https://github.com/nelo112) for work on improving compatibility with *nix OSes
* [schnee3](https://github.com/schnee3) for giving us some NCLOC support
* [drywolf](https://github.com/drywolf) for TSX support
* [drywolf](https://github.com/drywolf) for TSX file and better custom rule mapping

##With thanks
* The LCOV parser is directly copied from the community JavaScript SonarQube plug-in, which is LGPL'd.
53 changes: 21 additions & 32 deletions src/main/java/com/pablissimo/sonar/TsLintSensor.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,24 @@
package com.pablissimo.sonar;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import com.pablissimo.sonar.model.TsLintIssue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.config.Settings;
import org.sonar.api.issue.Issuable;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.ActiveRuleParam;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RuleQuery;
import org.sonar.api.batch.fs.FilePredicates;
import org.sonar.api.batch.fs.FileSystem;

import com.google.common.base.Charsets;
import com.google.common.base.Throwables;
import com.google.common.io.Files;
import com.google.gson.GsonBuilder;
import com.pablissimo.sonar.model.TsLintConfig;
import com.pablissimo.sonar.model.TsLintIssue;
import java.io.File;
import java.util.*;

public class TsLintSensor implements Sensor {
public static final String CONFIG_FILENAME = "tslint.json";
Expand Down Expand Up @@ -91,51 +76,51 @@ else if (pathToTsLintConfig == null) {

List<String> paths = new ArrayList<String>();
HashMap<String, File> fileMap = new HashMap<String, File>();

for (File file : fileSystem.files(this.filePredicates.hasLanguage(TypeScriptLanguage.LANGUAGE_KEY))) {
if (skipTypeDefFiles && file.getName().toLowerCase().endsWith("." + TypeScriptLanguage.LANGUAGE_DEFINITION_EXTENSION)) {
continue;
}

String pathAdjusted = file.getAbsolutePath().replace('\\', '/');
paths.add(pathAdjusted);
fileMap.put(pathAdjusted, file);
}

String jsonResult = executor.execute(pathToTsLint, pathToTsLintConfig, rulesDir, paths, tsLintTimeoutMs);

TsLintIssue[][] issues = parser.parse(jsonResult);

if (issues == null) {
LOG.warn("TsLint returned no result at all");
return;
}

// Each issue bucket will contain info about a single file
for (TsLintIssue[] batchIssues : issues) {
if (batchIssues == null || batchIssues.length == 0) {
continue;
}

String filePath = batchIssues[0].getName();

if (!fileMap.containsKey(filePath)) {
LOG.warn("TsLint reported issues against a file that wasn't sent to it - will be ignored: " + filePath);
continue;
}

File file = fileMap.get(filePath);
Resource resource = this.getFileFromIOFile(file, project);
Issuable issuable = perspectives.as(Issuable.class, resource);

for (TsLintIssue issue : batchIssues) {
// Make sure the rule we're violating is one we recognise - if not, we'll
// fall back to the generic 'tslint-issue' rule
String ruleName = issue.getRuleName();
if (!ruleNames.contains(ruleName)) {
ruleName = TsRulesDefinition.RULE_TSLINT_ISSUE;
ruleName = TsRulesDefinition.TSLINT_UNKNOWN_RULE.key;
}

issuable.addIssue
(
issuable
Expand All @@ -160,4 +145,8 @@ protected TsLintExecutor getTsLintExecutor() {
protected TsLintParser getTsLintParser() {
return new TsLintParserImpl();
}

protected TsRulesDefinition getTsRulesDefinition() {
return new TsRulesDefinition(this.settings);
}
}
Loading

0 comments on commit dd89fec

Please sign in to comment.