diff --git a/src/main/java/com/pablissimo/sonar/TsCoverageSensor.java b/src/main/java/com/pablissimo/sonar/TsCoverageSensor.java index cfdbaa9..45be597 100644 --- a/src/main/java/com/pablissimo/sonar/TsCoverageSensor.java +++ b/src/main/java/com/pablissimo/sonar/TsCoverageSensor.java @@ -84,6 +84,11 @@ protected void saveMeasureFromLCOVFile(Project project, SensorContext context) { LCOVParser parser = getParser(moduleFileSystem.baseDir()); Map coveredFiles = parser.parseFile(lcovFile); + + LOG.debug("Found coverage information for " + coveredFiles.size() + " files:"); + for (String key : coveredFiles.keySet()) { + LOG.debug(" " + key); + } final boolean ignoreNotFound = isIgnoreNotFoundActivated(); @@ -92,6 +97,9 @@ protected void saveMeasureFromLCOVFile(Project project, SensorContext context) { CoverageMeasuresBuilder fileCoverage = coveredFiles.get(file.getAbsolutePath()); org.sonar.api.resources.File resource = this.fileFromIoFile(file, project); + if (fileCoverage == null) { + LOG.debug("No coverage found for '" + file.getAbsolutePath() + "'"); + } if (fileCoverage != null) { for (Measure measure : fileCoverage.createMeasures()) { context.saveMeasure(resource, measure); diff --git a/src/main/java/com/pablissimo/sonar/TsLintExecutorImpl.java b/src/main/java/com/pablissimo/sonar/TsLintExecutorImpl.java index ed5d8d2..71b936f 100644 --- a/src/main/java/com/pablissimo/sonar/TsLintExecutorImpl.java +++ b/src/main/java/com/pablissimo/sonar/TsLintExecutorImpl.java @@ -1,10 +1,13 @@ package com.pablissimo.sonar; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.utils.System2; import org.sonar.api.utils.command.Command; import org.sonar.api.utils.command.CommandExecutor; import org.sonar.api.utils.command.StreamConsumer; @@ -15,24 +18,38 @@ public class TsLintExecutorImpl implements TsLintExecutor { private StringBuilder stdOut; private StringBuilder stdErr; + + private boolean mustQuoteSpaceContainingPaths = false; + + public TsLintExecutorImpl(System2 system) { + this.mustQuoteSpaceContainingPaths = system.isOsWindows(); + } + + private String preparePath(String path) { + if (path.contains(" ") && this.mustQuoteSpaceContainingPaths) { + return '"' + path + '"'; + } + + return path; + } - private static Command getBaseCommand(String pathToTsLint, String configFile, String rulesDir) { + private Command getBaseCommand(String pathToTsLint, String configFile, String rulesDir) { Command command = Command .create("node") - .addArgument('"' + pathToTsLint + '"') + .addArgument(this.preparePath(pathToTsLint)) .addArgument("--format") .addArgument("json"); - + if (rulesDir != null && rulesDir.length() > 0) { command .addArgument("--rules-dir") - .addArgument('"' + rulesDir + '"'); + .addArgument(this.preparePath(rulesDir)); } command .addArgument("--config") - .addArgument('"' + configFile + '"') + .addArgument(this.preparePath(configFile)) .setNewShell(false); return command; @@ -50,7 +67,7 @@ public String execute(String pathToTsLint, String configFile, String rulesDir, L int currentBatchLength = 0; for (int i = 0; i < files.size(); i++) { - String nextPath = '"' + files.get(i).trim() + '"'; + String nextPath = this.preparePath(files.get(i).trim()); // +1 for the space we'll be adding between filenames if (currentBatchLength + nextPath.length() + 1 > availableForBatching) { diff --git a/src/main/java/com/pablissimo/sonar/TsLintSensor.java b/src/main/java/com/pablissimo/sonar/TsLintSensor.java index 23b4d69..485ee3c 100644 --- a/src/main/java/com/pablissimo/sonar/TsLintSensor.java +++ b/src/main/java/com/pablissimo/sonar/TsLintSensor.java @@ -16,6 +16,7 @@ import org.sonar.api.rules.Rule; import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.RuleQuery; +import org.sonar.api.utils.System2; import java.io.File; import java.util.*; @@ -31,13 +32,15 @@ public class TsLintSensor implements Sensor { private FilePredicates filePredicates; private ResourcePerspectives perspectives; private RuleFinder ruleFinder; - - public TsLintSensor(Settings settings, FileSystem fileSystem, ResourcePerspectives perspectives, RuleFinder ruleFinder) { + private System2 system; + + public TsLintSensor(Settings settings, FileSystem fileSystem, ResourcePerspectives perspectives, RuleFinder ruleFinder, System2 system) { this.settings = settings; this.fileSystem = fileSystem; this.filePredicates = fileSystem.predicates(); this.perspectives = perspectives; this.ruleFinder = ruleFinder; + this.system = system; } public boolean shouldExecuteOnProject(Project project) { @@ -178,7 +181,7 @@ protected org.sonar.api.resources.File getFileFromIOFile(File file, Project proj } protected TsLintExecutor getTsLintExecutor() { - return new TsLintExecutorImpl(); + return new TsLintExecutorImpl(this.system); } protected TsLintParser getTsLintParser() { diff --git a/src/test/java/com/pablissimo/sonar/TsLintExecutorImplTest.java b/src/test/java/com/pablissimo/sonar/TsLintExecutorImplTest.java index fd439fc..90a0a34 100644 --- a/src/test/java/com/pablissimo/sonar/TsLintExecutorImplTest.java +++ b/src/test/java/com/pablissimo/sonar/TsLintExecutorImplTest.java @@ -10,6 +10,7 @@ import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import org.sonar.api.utils.System2; import org.sonar.api.utils.command.Command; import org.sonar.api.utils.command.CommandExecutor; import org.sonar.api.utils.command.StreamConsumer; @@ -19,11 +20,13 @@ public class TsLintExecutorImplTest { TsLintExecutorImpl executorImpl; CommandExecutor commandExecutor; + System2 system; @Before public void setUp() throws Exception { + this.system = mock(System2.class); this.commandExecutor = mock(CommandExecutor.class); - this.executorImpl = spy(new TsLintExecutorImpl()); + this.executorImpl = spy(new TsLintExecutorImpl(this.system)); when(this.executorImpl.createExecutor()).thenReturn(this.commandExecutor); } @@ -49,7 +52,7 @@ public Integer answer(InvocationOnMock invocation) throws Throwable { Command theCommand = capturedCommands.get(0); long theTimeout = capturedTimeouts.get(0); - assertEquals("node \"path/to/tslint\" --format json --rules-dir \"path/to/rules\" --config \"path/to/config\" \"path/to/file\" \"path/to/another\"", theCommand.toCommandLine()); + assertEquals("node path/to/tslint --format json --rules-dir path/to/rules --config path/to/config path/to/file path/to/another", theCommand.toCommandLine()); // Expect one timeout period per file processed assertEquals(2 * 40000, theTimeout); } @@ -105,7 +108,7 @@ public void BatchesExecutions_IfTooManyFilesForCommandLine() { String firstBatch = "first batch"; while (currentLength + 12 < TsLintExecutorImpl.MAX_COMMAND_LENGTH - standardCmdLength) { filenames.add(firstBatch); - currentLength += firstBatch.length() + 3; // 1 for the space, 2 for the quotes + currentLength += firstBatch.length() + 1; // 1 for the space } filenames.add("second batch"); diff --git a/src/test/java/com/pablissimo/sonar/TsLintSensorTest.java b/src/test/java/com/pablissimo/sonar/TsLintSensorTest.java index 220ede9..1ca2207 100644 --- a/src/test/java/com/pablissimo/sonar/TsLintSensorTest.java +++ b/src/test/java/com/pablissimo/sonar/TsLintSensorTest.java @@ -29,6 +29,7 @@ import com.pablissimo.sonar.model.TsLintPosition; import org.sonar.api.server.debt.DebtRemediationFunction; import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.api.utils.System2; public class TsLintSensorTest { Settings settings; @@ -39,6 +40,7 @@ public class TsLintSensorTest { FilePredicate predicate; Issuable issuable; IssueBuilder issueBuilder; + System2 system; List files; File file; @@ -51,6 +53,7 @@ public class TsLintSensorTest { @Before public void setUp() throws Exception { this.settings = mock(Settings.class); + this.system = mock(System2.class); when(this.settings.getString(TypeScriptPlugin.SETTING_TS_LINT_PATH)).thenReturn("/path/to/tslint"); when(this.settings.getString(TypeScriptPlugin.SETTING_TS_LINT_CONFIG_PATH)).thenReturn("/path/to/tslint.json"); when(this.settings.getInt(TypeScriptPlugin.SETTING_TS_LINT_TIMEOUT)).thenReturn(45000); @@ -143,7 +146,7 @@ public void setUp() throws Exception { this.executor = mock(TsLintExecutor.class); this.parser = mock(TsLintParser.class); - this.sensor = spy(new TsLintSensor(settings, fileSystem, perspectives, ruleFinder)); + this.sensor = spy(new TsLintSensor(settings, fileSystem, perspectives, ruleFinder, system)); doReturn(this.sonarFile).when(this.sensor).getFileFromIOFile(eq(this.file), any(Project.class)); doReturn(this.executor).when(this.sensor).getTsLintExecutor(); doReturn(this.parser).when(this.sensor).getTsLintParser(); @@ -243,7 +246,7 @@ public void analyze_callsExecutorWithAtLeast5000msTimeout() throws IOException { @Test public void check_getExecutor() { - TsLintSensor sensor = new TsLintSensor(settings, fileSystem, perspectives, ruleFinder); + TsLintSensor sensor = new TsLintSensor(settings, fileSystem, perspectives, ruleFinder, system); TsLintExecutor executor = sensor.getTsLintExecutor(); assertNotNull(executor); } @@ -251,7 +254,7 @@ public void check_getExecutor() @Test public void check_getParser() { - TsLintSensor sensor = new TsLintSensor(settings, fileSystem, perspectives, ruleFinder); + TsLintSensor sensor = new TsLintSensor(settings, fileSystem, perspectives, ruleFinder, system); TsLintParser parser = sensor.getTsLintParser(); assertNotNull(parser); } @@ -259,7 +262,7 @@ public void check_getParser() @Test public void check_getTsRulesDefinition() { - TsLintSensor sensor = new TsLintSensor(settings, fileSystem, perspectives, ruleFinder); + TsLintSensor sensor = new TsLintSensor(settings, fileSystem, perspectives, ruleFinder, system); TsRulesDefinition rulesDef = sensor.getTsRulesDefinition(); assertNotNull(rulesDef); }