From 98601129c049a67155ee0af7dacad512f1eb67c7 Mon Sep 17 00:00:00 2001 From: Tibor Blenessy Date: Tue, 11 May 2021 12:04:53 +0200 Subject: [PATCH] TypeScript sensor should skip analysis if no input files are found (#2620) --- .../it/plugin/EslintBasedRulesTest.java | 4 +++- .../javascript/eslint/AbstractEslintSensor.java | 11 +++++++++-- .../eslint/JavaScriptEslintBasedSensor.java | 10 +++++----- .../javascript/eslint/TypeScriptSensor.java | 7 ++++--- .../eslint/JavaScriptEslintBasedSensorTest.java | 17 ++++++++++++++++- .../javascript/eslint/TypeScriptSensorTest.java | 12 +++++++++++- 6 files changed, 48 insertions(+), 13 deletions(-) diff --git a/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/EslintBasedRulesTest.java b/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/EslintBasedRulesTest.java index 304130288ae..4847431d91e 100644 --- a/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/EslintBasedRulesTest.java +++ b/its/plugin/tests/src/test/java/com/sonar/javascript/it/plugin/EslintBasedRulesTest.java @@ -20,6 +20,7 @@ package com.sonar.javascript.it.plugin; import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.BuildResult; import com.sonar.orchestrator.build.SonarScanner; import com.sonar.orchestrator.locator.FileLocation; import java.io.File; @@ -67,7 +68,8 @@ public void testProject(File projectDir, String projectKey) { Tests.setProfile(projectKey, "rules", "js"); - orchestrator.executeBuild(build); + BuildResult buildResult = orchestrator.executeBuild(build); + assertThat(buildResult.getLogsLines(l -> l.startsWith("ERROR"))).isEmpty(); SearchRequest request = new SearchRequest(); request.setComponentKeys(singletonList(projectKey)).setRules(singletonList("javascript:S3923")); diff --git a/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/AbstractEslintSensor.java b/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/AbstractEslintSensor.java index 2a563b985e0..c560203d88a 100644 --- a/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/AbstractEslintSensor.java +++ b/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/AbstractEslintSensor.java @@ -116,8 +116,13 @@ public void execute(SensorContext context) { environments = Arrays.asList(context.config().getStringArray(ENVIRONMENTS_PROPERTY_KEY)); globals = Arrays.asList(context.config().getStringArray(GLOBALS_PROPERTY_KEY)); try { + List inputFiles = getInputFiles(); + if (inputFiles.isEmpty()) { + LOG.info("No input files found for analysis"); + return; + } startBridge(context); - analyzeFiles(); + analyzeFiles(inputFiles); } catch (CancellationException e) { // do not propagate the exception LOG.info(e.toString()); @@ -145,7 +150,9 @@ private void startBridge(SensorContext context) throws IOException { eslintBridgeServer.startServerLazily(context); } - abstract void analyzeFiles() throws IOException, InterruptedException; + abstract void analyzeFiles(List inputFiles) throws IOException; + + protected abstract List getInputFiles(); private void processParsingError(SensorContext sensorContext, InputFile inputFile, ParsingError parsingError) { Integer line = parsingError.line; diff --git a/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/JavaScriptEslintBasedSensor.java b/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/JavaScriptEslintBasedSensor.java index af1cdff6ffd..5ec3357f97a 100644 --- a/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/JavaScriptEslintBasedSensor.java +++ b/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/JavaScriptEslintBasedSensor.java @@ -77,8 +77,8 @@ public JavaScriptEslintBasedSensor(JavaScriptChecks checks, NoSonarFilter noSona } @Override - void analyzeFiles() throws IOException, InterruptedException { - runEslintAnalysis(provideDefaultTsConfig()); + void analyzeFiles(List inputFiles) throws IOException { + runEslintAnalysis(provideDefaultTsConfig(), inputFiles); if (checks.hasLegacyCustomChecks()) { PROFILER.startInfo("Java-based frontend sensor [javascript] for custom rules"); LOG.warn("Custom JavaScript rules are deprecated and API will be removed in future version."); @@ -97,11 +97,10 @@ private List provideDefaultTsConfig() throws IOException { return provider.tsconfigs(context); } - private void runEslintAnalysis(List tsConfigs) throws IOException, InterruptedException { + private void runEslintAnalysis(List tsConfigs, List inputFiles) throws IOException { ProgressReport progressReport = new ProgressReport("Analysis progress", TimeUnit.SECONDS.toMillis(10)); boolean success = false; try { - List inputFiles = getInputFiles(); progressReport.start(inputFiles.stream().map(InputFile::toString).collect(Collectors.toList())); eslintBridgeServer.initLinter(rules, environments, globals); for (InputFile inputFile : inputFiles) { @@ -137,7 +136,8 @@ private void analyze(InputFile file, List tsConfigs) throws IOException } } - private List getInputFiles() { + @Override + protected List getInputFiles() { FileSystem fileSystem = context.fileSystem(); FilePredicate mainFilePredicate = JavaScriptFilePredicate.getJavaScriptPredicate(fileSystem); return StreamSupport.stream(fileSystem.inputFiles(mainFilePredicate).spliterator(), false) diff --git a/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/TypeScriptSensor.java b/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/TypeScriptSensor.java index e3767a14428..5e46789c0c7 100644 --- a/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/TypeScriptSensor.java +++ b/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/eslint/TypeScriptSensor.java @@ -85,12 +85,14 @@ public TypeScriptSensor(TypeScriptChecks typeScriptChecks, NoSonarFilter noSonar @Override public void describe(SensorDescriptor descriptor) { descriptor + // JavaScriptLanguage.KEY is required for Vue single file components, bc .vue is considered as JS language .onlyOnLanguages(JavaScriptLanguage.KEY, TypeScriptLanguage.KEY) .name("TypeScript analysis") .onlyOnFileType(Type.MAIN); } - private List getInputFiles() { + @Override + protected List getInputFiles() { FileSystem fileSystem = context.fileSystem(); FilePredicate mainFilePredicate = JavaScriptFilePredicate.getTypeScriptPredicate(fileSystem); return StreamSupport.stream(fileSystem.inputFiles(mainFilePredicate).spliterator(), false) @@ -98,10 +100,9 @@ private List getInputFiles() { } @Override - void analyzeFiles() throws IOException, InterruptedException { + void analyzeFiles(List inputFiles) throws IOException { boolean success = false; ProgressReport progressReport = new ProgressReport("Progress of TypeScript analysis", TimeUnit.SECONDS.toMillis(10)); - List inputFiles = getInputFiles(); eslintBridgeServer.initLinter(rules, environments, globals); List tsConfigs = new TsConfigProvider(tempFolder).tsconfigs(context); if (tsConfigs.isEmpty()) { diff --git a/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/eslint/JavaScriptEslintBasedSensorTest.java b/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/eslint/JavaScriptEslintBasedSensorTest.java index 5283d348019..c4e8d1e9a1e 100644 --- a/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/eslint/JavaScriptEslintBasedSensorTest.java +++ b/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/eslint/JavaScriptEslintBasedSensorTest.java @@ -353,6 +353,19 @@ public void should_have_configured_rules() throws Exception { assertThat(rules.get(2).configurations).isEmpty(); } + @Test + public void should_skip_analysis_when_no_files() throws Exception { + JavaScriptEslintBasedSensor javaScriptEslintBasedSensor = new JavaScriptEslintBasedSensor(checks(ESLINT_BASED_RULE), + new NoSonarFilter(), + fileLinesContextFactory, + eslintBridgeServerMock, + mock(AnalysisWarnings.class), + tempFolder + ); + javaScriptEslintBasedSensor.execute(context); + assertThat(logTester.logs(LoggerLevel.INFO)).contains("No input files found for analysis"); + } + @Test public void handle_missing_node() throws Exception { doThrow(new NodeCommandException("Exception Message", new IOException())).when(eslintBridgeServerMock).startServerLazily(any()); @@ -364,7 +377,7 @@ public void handle_missing_node() throws Exception { analysisWarnings, tempFolder ); - + createInputFile(context); javaScriptEslintBasedSensor.execute(context); assertThat(logTester.logs(LoggerLevel.ERROR)).contains("Exception Message"); verify(analysisWarnings).addUnique("JavaScript and/or TypeScript rules were not executed. Exception Message"); @@ -374,6 +387,7 @@ public void handle_missing_node() throws Exception { public void log_debug_if_already_failed_server() throws Exception { doThrow(new ServerAlreadyFailedException()).when(eslintBridgeServerMock).startServerLazily(any()); JavaScriptEslintBasedSensor javaScriptEslintBasedSensor = createSensor(); + createInputFile(context); javaScriptEslintBasedSensor.execute(context); assertThat(logTester.logs()).contains("Skipping start of eslint-bridge server due to the failure during first analysis", @@ -475,6 +489,7 @@ public void should_fail_fast_with_nodecommandexception() throws Exception { JavaScriptEslintBasedSensor sensor = createSensor(); MapSettings settings = new MapSettings().setProperty("sonar.internal.analysis.failFast", true); context.setSettings(settings); + createInputFile(context); assertThatThrownBy(() -> sensor.execute(context)) .isInstanceOf(IllegalStateException.class) .hasMessage("Analysis failed (\"sonar.internal.analysis.failFast\"=true)"); diff --git a/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/eslint/TypeScriptSensorTest.java b/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/eslint/TypeScriptSensorTest.java index e8113a83983..9af3f54c209 100644 --- a/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/eslint/TypeScriptSensorTest.java +++ b/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/eslint/TypeScriptSensorTest.java @@ -426,13 +426,23 @@ private DefaultInputFile inputFileFromResource(SensorContextTester context, Path } @Test - public void should_stop_without_tsconfig() { + public void should_stop_without_tsconfig() throws Exception { + Path baseDir = Paths.get("src/test/resources/solution-tsconfig"); SensorContextTester context = SensorContextTester.create(tempFolder.newDir()); + inputFileFromResource(context, baseDir, "src/file.ts"); + context.setRuntime(SonarRuntimeImpl.forSonarLint(Version.create(4, 4))); createSensor().execute(context); assertThat(logTester.logs(LoggerLevel.WARN)).contains("No tsconfig.json file found, analysis will be skipped."); } + @Test + public void should_stop_when_no_input_files() throws Exception { + SensorContextTester context = SensorContextTester.create(tempFolder.newDir()); + createSensor().execute(context); + assertThat(logTester.logs()).containsOnly("No input files found for analysis"); + } + @Test public void should_fail_fast() throws Exception { when(eslintBridgeServerMock.analyzeTypeScript(any())).thenThrow(new IOException("error"));