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

Commit

Permalink
Merging @NikitaEgorov changes for using existing tslint output file PR
Browse files Browse the repository at this point in the history
  • Loading branch information
Pablissimo committed Feb 4, 2017

Verified

This commit was signed with the committer’s verified signature.
Pablissimo Paul O'Neill
2 parents dbece6b + 1065a4d commit 31bc889
Showing 7 changed files with 214 additions and 137 deletions.
29 changes: 22 additions & 7 deletions src/main/java/com/pablissimo/sonar/TsLintExecutorConfig.java
Original file line number Diff line number Diff line change
@@ -6,29 +6,35 @@
public class TsLintExecutorConfig {
public static final String CONFIG_FILENAME = "tslint.json";
public static final String TSLINT_FALLBACK_PATH = "node_modules/tslint/bin/tslint";

private String pathToTsLint;
private String configFile;
private String rulesDir;
private String pathToTsConfig;
private boolean shouldPerformTypeCheck;

private String pathToTsLintOutput;

private Integer timeoutMs;

public static TsLintExecutorConfig fromSettings(Settings settings, SensorContext ctx, PathResolver resolver) {
TsLintExecutorConfig toReturn = new TsLintExecutorConfig();

toReturn.setPathToTsLint(resolver.getPath(ctx, TypeScriptPlugin.SETTING_TS_LINT_PATH, TSLINT_FALLBACK_PATH));
toReturn.setConfigFile(resolver.getPath(ctx, TypeScriptPlugin.SETTING_TS_LINT_CONFIG_PATH, CONFIG_FILENAME));
toReturn.setRulesDir(resolver.getPath(ctx, TypeScriptPlugin.SETTING_TS_LINT_RULES_DIR, null));
toReturn.setPathToTsConfig(resolver.getPath(ctx, TypeScriptPlugin.SETTING_TS_LINT_PROJECT_PATH, null));

toReturn.setPathToTsLintOutput(resolver.getPath(ctx, TypeScriptPlugin.SETTING_TS_LINT_OUTPUT_PATH, null));

toReturn.setTimeoutMs(Math.max(5000, settings.getInt(TypeScriptPlugin.SETTING_TS_LINT_TIMEOUT)));
toReturn.setShouldPerformTypeCheck(settings.getBoolean(TypeScriptPlugin.SETTING_TS_LINT_TYPECHECK));

return toReturn;
}


public Boolean useExistingTsLintOutput() {
return this.pathToTsLintOutput != null && !this.pathToTsLintOutput.isEmpty();
}

public Boolean useTsConfigInsteadOfFileList() {
return this.pathToTsConfig != null && !this.pathToTsConfig.isEmpty();
}
@@ -73,6 +79,15 @@ public void setPathToTsConfig(String pathToTsConfig) {
this.pathToTsConfig = pathToTsConfig;
}

public String getPathToTsLintOutput() {
return this.pathToTsLintOutput;
}

public void setPathToTsLintOutput(String pathToTsLintOutput) {
this.pathToTsLintOutput = pathToTsLintOutput;
}


public boolean shouldPerformTypeCheck() {
return this.shouldPerformTypeCheck;
}
69 changes: 40 additions & 29 deletions src/main/java/com/pablissimo/sonar/TsLintExecutorImpl.java
Original file line number Diff line number Diff line change
@@ -23,12 +23,12 @@ public class TsLintExecutorImpl implements TsLintExecutor {

private boolean mustQuoteSpaceContainingPaths = false;
private TempFolder tempFolder;

public TsLintExecutorImpl(System2 system, TempFolder tempFolder) {
this.mustQuoteSpaceContainingPaths = system.isOsWindows();
this.tempFolder = tempFolder;
}

private String preparePath(String path) {
if (path == null) {
return null;
@@ -40,7 +40,7 @@ else if (path.contains(" ") && this.mustQuoteSpaceContainingPaths) {
return path;
}
}

private Command getBaseCommand(TsLintExecutorConfig config, String tempPath) {
Command command =
Command
@@ -55,7 +55,7 @@ private Command getBaseCommand(TsLintExecutorConfig config, String tempPath) {
.addArgument("--rules-dir")
.addArgument(this.preparePath(rulesDir));
}

if (tempPath != null && tempPath.length() > 0) {
command
.addArgument("--out")
@@ -65,13 +65,13 @@ private Command getBaseCommand(TsLintExecutorConfig config, String tempPath) {
command
.addArgument("--config")
.addArgument(this.preparePath(config.getConfigFile()));

if (config.useTsConfigInsteadOfFileList()) {
command
.addArgument("--project")
.addArgument(this.preparePath(config.getPathToTsConfig()));
}

if (config.shouldPerformTypeCheck()) {
command
.addArgument("--type-check");
@@ -89,66 +89,73 @@ public List<String> execute(TsLintExecutorConfig config, List<String> files) {
else if (files == null) {
throw new IllegalArgumentException("files");
}


if (config.useExistingTsLintOutput()) {
LOG.debug("Running with existing JSON file '" + config.getPathToTsLintOutput() + "' instead of calling tslint");
List<String> toReturn = new ArrayList<String>();
toReturn.add(this.getFileContent(new File(config.getPathToTsLintOutput())));
return toReturn;
}

// New up a command that's everything we need except the files to process
// We'll use this as our reference for chunking up files, if we need to
File tslintOutputFile = this.tempFolder.newFile();
String tslintOutputFilePath = tslintOutputFile.getAbsolutePath();
Command baseCommand = getBaseCommand(config, tslintOutputFilePath);

LOG.debug("Using a temporary path for TsLint output: " + tslintOutputFilePath);

StringStreamConsumer stdOutConsumer = new StringStreamConsumer();
StringStreamConsumer stdErrConsumer = new StringStreamConsumer();

List<String> toReturn = new ArrayList<String>();

if (config.useTsConfigInsteadOfFileList()) {
LOG.debug("Running against a single project JSON file");

// If we're being asked to use a tsconfig.json file, it'll contain
// the file list to lint - so don't batch, and just run with it
toReturn.add(this.getCommandOutput(baseCommand, stdOutConsumer, stdErrConsumer, tslintOutputFile, config.getTimeoutMs()));
}
else {
else {
int baseCommandLength = baseCommand.toCommandLine().length();
int availableForBatching = MAX_COMMAND_LENGTH - baseCommandLength;

List<List<String>> batches = new ArrayList<List<String>>();
List<String> currentBatch = new ArrayList<String>();
batches.add(currentBatch);

int currentBatchLength = 0;
for (int i = 0; i < files.size(); i++) {
String nextPath = this.preparePath(files.get(i).trim());

// +1 for the space we'll be adding between filenames
if (currentBatchLength + nextPath.length() + 1 > availableForBatching) {
// Too long to add to this batch, create new
currentBatch = new ArrayList<String>();
currentBatchLength = 0;
batches.add(currentBatch);
}

currentBatch.add(nextPath);
currentBatchLength += nextPath.length() + 1;
}

LOG.debug("Split " + files.size() + " files into " + batches.size() + " batches for processing");

for (int i = 0; i < batches.size(); i++) {
StringBuilder outputBuilder = new StringBuilder();

List<String> thisBatch = batches.get(i);

Command thisCommand = getBaseCommand(config, tslintOutputFilePath);

for (int fileIndex = 0; fileIndex < thisBatch.size(); fileIndex++) {
thisCommand.addArgument(thisBatch.get(fileIndex));
}

LOG.debug("Executing TsLint with command: " + thisCommand.toCommandLine());

// Timeout is specified per file, not per batch (which can vary a lot)
// so multiply it up
toReturn.add(this.getCommandOutput(thisCommand, stdOutConsumer, stdErrConsumer, tslintOutputFile, config.getTimeoutMs() * thisBatch.size()));
@@ -157,35 +164,39 @@ else if (files == null) {

return toReturn;
}

private String getCommandOutput(Command thisCommand, StreamConsumer stdOutConsumer, StreamConsumer stdErrConsumer, File tslintOutputFile, Integer timeoutMs) {
LOG.debug("Executing TsLint with command: " + thisCommand.toCommandLine());

// Timeout is specified per file, not per batch (which can vary a lot)
// so multiply it up
this.createExecutor().execute(thisCommand, stdOutConsumer, stdErrConsumer, timeoutMs);

return getFileContent(tslintOutputFile);
}

private String getFileContent(File tslintOutputFile) {
StringBuilder outputBuilder = new StringBuilder();

try {
BufferedReader reader = this.getBufferedReaderForFile(tslintOutputFile);

String str;
while ((str = reader.readLine()) != null) {
outputBuilder.append(str);
}

reader.close();

return outputBuilder.toString();
}
catch (IOException ex) {
LOG.error("Failed to re-read TsLint output", ex);
}

return "";
}

protected BufferedReader getBufferedReaderForFile(File file) throws IOException {
return new BufferedReader(
new InputStreamReader(
26 changes: 13 additions & 13 deletions src/main/java/com/pablissimo/sonar/TsLintSensor.java
Original file line number Diff line number Diff line change
@@ -22,15 +22,15 @@ public class TsLintSensor implements Sensor {
private PathResolver resolver;
private TsLintExecutor executor;
private TsLintParser parser;
public TsLintSensor(Settings settings, PathResolver resolver,

public TsLintSensor(Settings settings, PathResolver resolver,
TsLintExecutor executor, TsLintParser parser) {
this.settings = settings;
this.resolver = resolver;
this.executor = executor;
this.parser = parser;
}

@Override
public void describe(SensorDescriptor desc) {
desc
@@ -39,14 +39,14 @@ public void describe(SensorDescriptor desc) {
}

@Override
public void execute(SensorContext ctx) {
public void execute(SensorContext ctx) {
if (!this.settings.getBoolean(TypeScriptPlugin.SETTING_TS_LINT_ENABLED)) {
LOG.debug("Skipping tslint execution - " + TypeScriptPlugin.SETTING_TS_LINT_ENABLED + " set to false");
return;
}

TsLintExecutorConfig config = TsLintExecutorConfig.fromSettings(this.settings, ctx, this.resolver);

if (config.getPathToTsLint() == null) {
LOG.warn("Path to tslint not defined or not found. Skipping tslint analysis.");
return;
@@ -76,7 +76,7 @@ else if (config.getConfigFile() == null && config.getPathToTsConfig() == null) {
paths.add(pathAdjusted);
fileMap.put(pathAdjusted, file);
}

List<String> jsonResults = this.executor.execute(config, paths);

Map<String, List<TsLintIssue>> issues = this.parser.parse(jsonResults);
@@ -89,7 +89,7 @@ else if (config.getConfigFile() == null && config.getPathToTsConfig() == null) {
// Each issue bucket will contain info about a single file
for (String filePath : issues.keySet()) {
List<TsLintIssue> batchIssues = issues.get(filePath);

if (batchIssues == null || batchIssues.size() == 0) {
continue;
}
@@ -100,7 +100,7 @@ else if (config.getConfigFile() == null && config.getPathToTsConfig() == null) {
}

InputFile file = fileMap.get(filePath);

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
@@ -109,18 +109,18 @@ else if (config.getConfigFile() == null && config.getPathToTsConfig() == null) {
ruleName = TsRulesDefinition.TSLINT_UNKNOWN_RULE.key;
}

NewIssue newIssue =
NewIssue newIssue =
ctx
.newIssue()
.forRule(RuleKey.of(TsRulesDefinition.REPOSITORY_NAME, ruleName));
NewIssueLocation newIssueLocation =

NewIssueLocation newIssueLocation =
newIssue
.newLocation()
.on(file)
.message(issue.getFailure())
.at(file.selectLine(issue.getStartPosition().getLine() + 1));

newIssue.at(newIssueLocation);
newIssue.save();
}
18 changes: 14 additions & 4 deletions src/main/java/com/pablissimo/sonar/TypeScriptPlugin.java
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@
description = "Maximum time to wait for TsLint execution to finish before aborting (in milliseconds)",
project = true,
global = false
)/*,
),
@Property(
key = TypeScriptPlugin.SETTING_TS_LINT_TYPECHECK,
defaultValue = "false",
@@ -102,14 +102,23 @@
global = false
),
@Property(
key = TypeScriptPlugin.SETTING_TS_LINT_TSCONFIG_PATH,
key = TypeScriptPlugin.SETTING_TS_LINT_PROJECT_PATH,
defaultValue = "",
type = PropertyType.STRING,
name = "Path to tsconfig.json file, if required",
description = "Required if tslinttypecheck parameter specified, the path to the tsconfig.json file that describes the files to lint and build",
project = true,
global = false
)*/
),
@Property(
key = TypeScriptPlugin.SETTING_TS_LINT_OUTPUT_PATH,
defaultValue = "",
type = PropertyType.STRING,
name = "Path to TSLint JSON output file",
description = "If set, the contents of this file will be used to discover linting issues rather than the plugin running tslint itself",
project = true,
global = false
)
})
public class TypeScriptPlugin implements Plugin {
public static final String SETTING_EXCLUDE_TYPE_DEFINITION_FILES = "sonar.ts.excludetypedefinitionfiles";
@@ -124,6 +133,7 @@ public class TypeScriptPlugin implements Plugin {
public static final String SETTING_TS_RULE_CONFIGS = "sonar.ts.ruleconfigs";
public static final String SETTING_TS_LINT_TYPECHECK = "sonar.ts.tslinttypecheck";
public static final String SETTING_TS_LINT_PROJECT_PATH = "sonar.ts.tslintprojectpath";
public static final String SETTING_TS_LINT_OUTPUT_PATH = "sonar.ts.tslintoutputpath";

@Override
public void define(Context ctx) {
@@ -135,7 +145,7 @@ public void define(Context ctx) {
.addExtension(TsLintSensor.class)
.addExtension(CombinedCoverageSensor.class)
.addExtension(TsRulesDefinition.class);

// Additional services to be DI'd into the above
ctx.addExtension(PathResolverImpl.class);
ctx.addExtension(TsLintExecutorImpl.class);
Loading

0 comments on commit 31bc889

Please sign in to comment.