From b02aa5ecd39c2b8027c3cf90b65d62c30a05299b Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Wed, 12 Aug 2020 19:59:18 +0200 Subject: [PATCH 01/25] Prepare next release --- CHANGELOG.md | 19 +++++++++++++++++++ dart-lang/pom.xml | 2 +- pom.xml | 2 +- sonar-flutter-plugin/pom.xml | 4 ++-- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7cf170..f29d273 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # SonarQube Plugin for Flutter / Dart +## develop + +#### Breaking + +- None. + +#### Experimental + +- None. + +#### Enhancements + +- None. + +#### Bug Fixes + +- None. + + ## 0.3.1 #### Breaking diff --git a/dart-lang/pom.xml b/dart-lang/pom.xml index 57104c3..5122dbb 100644 --- a/dart-lang/pom.xml +++ b/dart-lang/pom.xml @@ -3,7 +3,7 @@ sonar-flutter fr.insideapp.sonarqube - 0.3.1 + 0.3-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index e7c3558..a7d7d57 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ fr.insideapp.sonarqube sonar-flutter - 0.3.1 + 0.3-SNAPSHOT pom diff --git a/sonar-flutter-plugin/pom.xml b/sonar-flutter-plugin/pom.xml index 431b867..3c4312a 100644 --- a/sonar-flutter-plugin/pom.xml +++ b/sonar-flutter-plugin/pom.xml @@ -4,7 +4,7 @@ sonar-flutter fr.insideapp.sonarqube - 0.3.1 + 0.3-SNAPSHOT 4.0.0 @@ -17,7 +17,7 @@ fr.insideapp.sonarqube dart-lang - 0.3.1 + 0.3-SNAPSHOT From c9c4b001c8a9fe3def7b2eda2506d792d4b653ca Mon Sep 17 00:00:00 2001 From: Peter Leibiger Date: Tue, 18 Aug 2020 14:25:21 +0200 Subject: [PATCH 02/25] Add some missing Dart keywords --- CHANGELOG.md | 2 +- dart-lang/src/main/resources/dart.keywords | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f29d273..53c309e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ #### Enhancements -- None. +- Add missing dart keywords `extension`, `on`, `mixin` #### Bug Fixes diff --git a/dart-lang/src/main/resources/dart.keywords b/dart-lang/src/main/resources/dart.keywords index 2a608b1..746a34e 100644 --- a/dart-lang/src/main/resources/dart.keywords +++ b/dart-lang/src/main/resources/dart.keywords @@ -14,8 +14,9 @@ do$dynamic else enum export -external extends +extension +external factory false final @@ -28,8 +29,10 @@ import in is library +mixin new null +on operator part rethrow @@ -48,4 +51,3 @@ void while with yield - From 67d73dc38b9f922644058d6d68d85c1ca46a1a98 Mon Sep 17 00:00:00 2001 From: Peter Leibiger Date: Tue, 18 Aug 2020 16:12:43 +0200 Subject: [PATCH 03/25] Allow reuse of an existing dartanalyzer report --- CHANGELOG.md | 2 +- .../sonarqube/dart/lang/DartSensor.java | 1 + .../dart/lang/SourceLinesProvider.java | 2 +- .../dartanalyzer/DartAnalyzerSensor.java | 509 ++++++++++-------- .../sonarqube/flutter/FlutterPlugin.java | 9 + 5 files changed, 282 insertions(+), 241 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f29d273..e83ba0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ #### Enhancements -- None. +- Allow re-using an existing dartanalyzer report with `sonar.dart.analysis.reportPath` #### Bug Fixes diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/DartSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/DartSensor.java index 6aaa9f2..abef2ed 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/DartSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/DartSensor.java @@ -45,6 +45,7 @@ public class DartSensor implements Sensor { private static final Logger LOGGER = LoggerFactory.getLogger(DartSensor.class); private static final int EXECUTOR_TIMEOUT = 10000; public static final String DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY = "sonar.dart.analysis.useExistingOptions"; + public static final String DART_ANALYSIS_USE_EXISTING_REPORT_PATH_KEY = "sonar.dart.analysis.reportPath"; @Override public void describe(SensorDescriptor sensorDescriptor) { diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/SourceLinesProvider.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/SourceLinesProvider.java index 493f506..d9c3a6a 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/SourceLinesProvider.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/SourceLinesProvider.java @@ -59,7 +59,7 @@ public SourceLine[] getLines(final InputStream inputStream, final Charset charse } sourceLines.add(new SourceLine(totalLines, count, global - count, global)); } catch (final Throwable e) { - LOGGER.warn("Error occured reading file", e); + LOGGER.warn("Error occurred reading file", e); } return sourceLines.toArray(new SourceLine[0]); diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index 1cf7d4e..76d8e89 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -19,7 +19,6 @@ */ package fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer; -import com.google.common.io.Files; import com.google.common.io.Resources; import fr.insideapp.sonarqube.dart.lang.Dart; import fr.insideapp.sonarqube.dart.lang.DartSensor; @@ -37,9 +36,11 @@ import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation; import org.sonar.api.rule.RuleKey; +import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.net.URL; +import java.nio.file.Files; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -47,242 +48,272 @@ import java.util.stream.Collectors; public class DartAnalyzerSensor implements Sensor { - private static final Logger LOGGER = LoggerFactory.getLogger(DartAnalyzerSensor.class); - private static final String ANALYZER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") - ? "dartanalyzer.bat" - : "dartanalyzer"; - private static final int ANALYZER_TIMEOUT = 10 * 60 * 1000; - private static final String ANALYSIS_OPTIONS_FILENAME = "analysis_options.yaml"; - private static final String ANALYSIS_OPTIONS_FILE = "/fr/insideapp/sonarqube/dart/dartanalyzer/analysis_options.yaml"; - private static final Integer PAGE_SIZE = 50; - private boolean useExistingAnalysisOptions; - - @Override - public void describe(SensorDescriptor sensorDescriptor) { - sensorDescriptor.onlyOnLanguage(Dart.KEY).name("dartanalyzer sensor").onlyOnFileType(Type.MAIN); - } - - @Override - public void execute(SensorContext sensorContext) { - try { - verifyIfDartAnalyzerExists(); - - selectOptionFileToUse(sensorContext); - - recordIssues(sensorContext, buildIssues(getFilesWithAbsolutePath(sensorContext))); - - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } finally { - if (!useExistingAnalysisOptions) { - restoreCurrentAnalysisOptionsFile(sensorContext); - } - } - } - - private void selectOptionFileToUse(SensorContext sensorContext) throws IOException { - useExistingAnalysisOptions = getUseExistingAnalysisOptions(sensorContext); - - // Usage of existing option is required but file is missing - // Or usage of existing option is not required - if ((useExistingAnalysisOptions && !this.existsAnalysisOptionsFile(sensorContext)) || !useExistingAnalysisOptions) { - useDefaultAnalysisOptionsFile(sensorContext); - } - } - - private void useDefaultAnalysisOptionsFile(SensorContext sensorContext) throws IOException { - LOGGER.debug("Either {} option is not set to true or {} file does not exists, use default analysis options instead", - DartSensor.DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY, ANALYSIS_OPTIONS_FILENAME); - - useExistingAnalysisOptions = false; - - this.saveCurrentAnalysisOptionsFile(sensorContext); - this.createAnalysisOptionsFile(sensorContext); - } - - private Boolean getUseExistingAnalysisOptions(SensorContext sensorContext) { - return sensorContext.config().getBoolean(DartSensor.DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY).orElse(false); - } - - private List buildIssues(List filesWithAbsolutePath) - throws IOException { - Set issues = new HashSet<>(); - - for (String paginatedFileBatch : getPaginatedFilesPaths(filesWithAbsolutePath)) { - - LOGGER.debug("Current file batch: {}", paginatedFileBatch); - - try { - String output = new ProcBuilder(ANALYZER_COMMAND) - .withArgs(paginatedFileBatch.split(" ")) - .withTimeoutMillis(ANALYZER_TIMEOUT) - //.withExpectedExitStatuses(0, 1, 2, 3) - .ignoreExitStatus() - .run() - .getOutputString(); - - issues.addAll(new DartAnalyzerReportParser().parse(output)); - } catch (Exception e) { - throw new IOException(e); - } - - - } - LOGGER.debug("Found issues: {}", issues.size()); - List result = new ArrayList<>(); - result.addAll(issues); - return result; - } - - private List getPaginatedFilesPaths(List filesWithAbsolutePath) { - List paginated = new ArrayList(); - - LOGGER.debug("Paging the files to execute the analyzer..."); - - Integer pagingStart = 0; - Integer pagingRemainder = getPaginationRemainder(filesWithAbsolutePath); - Integer totalPages = getPaginationTotalPages(filesWithAbsolutePath, PAGE_SIZE, pagingRemainder); - - for (int i = 0; i < totalPages; i++) { - LOGGER.debug("Current index: {}", i); - - LOGGER.debug("Current paging start: {}", pagingStart); - - Integer pagingEnd = getPagingEnd(pagingStart, pagingRemainder, totalPages, i); - - paginated.add(getFilesPathsSplitBySpace(filesWithAbsolutePath, pagingStart, pagingEnd)); - - pagingStart += PAGE_SIZE; - } - return paginated; - } - - private Integer getPagingEnd(Integer pagingStart, Integer pagingRemainder, Integer totalPages, int i) { - Integer pagingEnd = pagingStart + PAGE_SIZE; - if (isLastPage(pagingRemainder, totalPages, i)) { - pagingEnd = pagingStart + pagingRemainder; - } - LOGGER.debug("Current paging end: {}", pagingEnd); - return pagingEnd; - } - - private String getFilesPathsSplitBySpace(List filesWithAbsolutePath, Integer pagingStart, - Integer pagingEnd) { - return filesWithAbsolutePath.subList(pagingStart, pagingEnd).stream().collect(Collectors.joining(" ")); - } - - private boolean isLastPage(Integer pagingRemainder, Integer totalPages, int i) { - return pagingRemainder != 0 && i + 1 == totalPages; - } - - private Integer getPaginationRemainder(List filesWithAbsolutePath) { - Integer remainder = filesWithAbsolutePath.size() % PAGE_SIZE; - - LOGGER.debug("Paging remainder: {}", remainder); - - return remainder; - } - - private Integer getPaginationTotalPages(List filesWithAbsolutePath, final Integer PAGE_SIZE, - Integer remainder) { - Integer total = filesWithAbsolutePath.size() / PAGE_SIZE; - - if (remainder != 0) { - total++; - } - LOGGER.debug("Paging total items: {}", total); - return total; - } - - private List getFilesWithAbsolutePath(SensorContext sensorContext) { - List filesWithAbsolutePath = new ArrayList<>(); - - FileSystem fileSystem = getFileSystem(sensorContext); - - FilePredicate mainFilePredicate = getFilesFilter(fileSystem); - - String absolutePath = fileSystem.baseDir().getAbsolutePath(); - - LOGGER.debug("Files absolute path: {}", absolutePath); - - fileSystem.inputFiles(mainFilePredicate).forEach(s -> { - LOGGER.debug("Input file path: {}", s.toString()); - - String fullPath = new StringBuilder(absolutePath).append(File.separator).append(s.toString().replace("/", File.separator)) - .toString(); - - LOGGER.debug("Current file full path: {}", fullPath); - - filesWithAbsolutePath.add(fullPath); - }); - - return filesWithAbsolutePath; - } - - private FilePredicate getFilesFilter(FileSystem fileSystem) { - FilePredicate mainFilePredicate = fileSystem.predicates().and( - fileSystem.predicates().hasType(InputFile.Type.MAIN), fileSystem.predicates().hasLanguage(Dart.KEY)); - return mainFilePredicate; - } - - private FileSystem getFileSystem(SensorContext sensorContext) { - FileSystem fileSystem = sensorContext.fileSystem(); - return fileSystem; - } - - private void recordIssues(SensorContext sensorContext, List issues) { - // Record issues - issues.forEach(i -> { - File file = new File(sensorContext.fileSystem().baseDir(), i.getFilePath()); - LOGGER.debug("Inside issue forEach, file absolute path: {}", file.getAbsolutePath()); - - FilePredicate fp = sensorContext.fileSystem().predicates().hasAbsolutePath(file.getAbsolutePath()); - if (!sensorContext.fileSystem().hasFiles(fp)) { - LOGGER.warn("File not included in SonarQube {}", file.getAbsoluteFile()); - } else { - InputFile inputFile = sensorContext.fileSystem().inputFile(fp); - NewIssueLocation nil = new DefaultIssueLocation().on(inputFile) - .at(inputFile.selectLine(i.getLineNumber())).message(i.getMessage()); - sensorContext.newIssue().forRule(RuleKey.of(DartAnalyzerRulesDefinition.REPOSITORY_KEY, i.getRuleId())) - .at(nil).save(); - } - }); - } - - private void verifyIfDartAnalyzerExists() { - LOGGER.debug("Verify dart analyser..."); - new ProcBuilder(ANALYZER_COMMAND).withArg("-h").run(); - LOGGER.debug("Verify dart analyser done"); - } - - private boolean existsAnalysisOptionsFile(SensorContext sensorContext) { - return new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME).exists(); - } - - private void saveCurrentAnalysisOptionsFile(SensorContext sensorContext) { - File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); - if (analysisOptionsFile.exists()) { - analysisOptionsFile - .renameTo(new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME + ".sonar")); - LOGGER.info("Backup of original analysis_options.yaml file to {}", ANALYSIS_OPTIONS_FILENAME + ".sonar"); - } - } - - private void createAnalysisOptionsFile(SensorContext sensorContext) throws IOException { - File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); - URL inputUrl = getClass().getResource(ANALYSIS_OPTIONS_FILE); - Resources.asByteSource(inputUrl).copyTo(Files.asByteSink(analysisOptionsFile)); - } - - private void restoreCurrentAnalysisOptionsFile(SensorContext sensorContext) { - File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); - File currentAnalysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), - ANALYSIS_OPTIONS_FILENAME + ".sonar"); - if (currentAnalysisOptionsFile.exists()) { - currentAnalysisOptionsFile.renameTo(analysisOptionsFile); - LOGGER.info("Restored original analysis_options.yaml file"); - } else { - analysisOptionsFile.delete(); - } - } + private static final Logger LOGGER = LoggerFactory.getLogger(DartAnalyzerSensor.class); + private static final String ANALYZER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") + ? "dartanalyzer.bat" + : "dartanalyzer"; + private static final int ANALYZER_TIMEOUT = 10 * 60 * 1000; + private static final String ANALYSIS_OPTIONS_FILENAME = "analysis_options.yaml"; + private static final String ANALYSIS_OPTIONS_FILE = "/fr/insideapp/sonarqube/dart/dartanalyzer/analysis_options.yaml"; + private static final Integer PAGE_SIZE = 50; + private boolean useExistingAnalysisOptions; + + @Override + public void describe(SensorDescriptor sensorDescriptor) { + sensorDescriptor.onlyOnLanguage(Dart.KEY).name("dartanalyzer sensor").onlyOnFileType(Type.MAIN); + } + + @Override + public void execute(@Nonnull SensorContext sensorContext) { + try { + if (sensorContext.config().hasKey(DartSensor.DART_ANALYSIS_USE_EXISTING_REPORT_PATH_KEY)) { + executeWithExistingReport(sensorContext); + } else { + executeWithAnalyzer(sensorContext); + } + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + } + + private void executeWithExistingReport(SensorContext sensorContext) throws IOException { + final String path = sensorContext.config().get(DartSensor.DART_ANALYSIS_USE_EXISTING_REPORT_PATH_KEY) + .orElseThrow(() -> new IllegalArgumentException(DartSensor.DART_ANALYSIS_USE_EXISTING_REPORT_PATH_KEY + " is miss-configured!")); + final File report = sensorContext.fileSystem().resolvePath(path); + LOGGER.info("Analysing report from " + report.getPath()); + List issues = buildIssuesFromFile(report); + recordIssues(sensorContext, issues); + } + + + private void executeWithAnalyzer(SensorContext sensorContext) throws IOException { + try { + verifyIfDartAnalyzerExists(); + selectOptionFileToUse(sensorContext); + LOGGER.info("Analysing with dartanalyzer"); + final List issues = buildIssues(getFilesWithAbsolutePath(sensorContext)); + recordIssues(sensorContext, issues); + } finally { + if (!useExistingAnalysisOptions) { + restoreCurrentAnalysisOptionsFile(sensorContext); + } + } + } + + private void selectOptionFileToUse(SensorContext sensorContext) throws IOException { + useExistingAnalysisOptions = getUseExistingAnalysisOptions(sensorContext); + + // Usage of existing option is required but file is missing + // Or usage of existing option is not required + if (!useExistingAnalysisOptions || !this.existsAnalysisOptionsFile(sensorContext)) { + useDefaultAnalysisOptionsFile(sensorContext); + } + } + + private void useDefaultAnalysisOptionsFile(SensorContext sensorContext) throws IOException { + LOGGER.debug("Either {} option is not set to true or {} file does not exists, use default analysis options instead", + DartSensor.DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY, ANALYSIS_OPTIONS_FILENAME); + + useExistingAnalysisOptions = false; + + this.saveCurrentAnalysisOptionsFile(sensorContext); + this.createAnalysisOptionsFile(sensorContext); + } + + private Boolean getUseExistingAnalysisOptions(SensorContext sensorContext) { + return sensorContext.config().getBoolean(DartSensor.DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY).orElse(false); + } + + private List buildIssues(List filesWithAbsolutePath) + throws IOException { + + for (String paginatedFileBatch : getPaginatedFilesPaths(filesWithAbsolutePath)) { + + LOGGER.debug("Current file batch: {}", paginatedFileBatch); + + try { + String output = new ProcBuilder(ANALYZER_COMMAND) + .withArgs(paginatedFileBatch.split(" ")) + .withTimeoutMillis(ANALYZER_TIMEOUT) + //.withExpectedExitStatuses(0, 1, 2, 3) + .ignoreExitStatus() + .run() + .getOutputString(); + + return createIssuesFromOutput(output); + } catch (Exception e) { + throw new IOException(e); + } + } + LOGGER.debug("Found no issues"); + return new ArrayList<>(); + } + + private List buildIssuesFromFile(File report) + throws IOException { + if (report != null && report.exists() && report.canRead()) { + final String output = new String(Files.readAllBytes(report.toPath())); + return createIssuesFromOutput(output); + } else { + throw new IllegalArgumentException("File does not exist or could not be read!"); + } + } + + private List createIssuesFromOutput(String output) { + Set issues = new HashSet<>(new DartAnalyzerReportParser().parse(output)); + LOGGER.debug("Found issues: {}", issues.size()); + return new ArrayList<>(issues); + } + + private List getPaginatedFilesPaths(List filesWithAbsolutePath) { + List paginated = new ArrayList(); + + LOGGER.debug("Paging the files to execute the analyzer..."); + + Integer pagingStart = 0; + Integer pagingRemainder = getPaginationRemainder(filesWithAbsolutePath); + Integer totalPages = getPaginationTotalPages(filesWithAbsolutePath, PAGE_SIZE, pagingRemainder); + + for (int i = 0; i < totalPages; i++) { + LOGGER.debug("Current index: {}", i); + + LOGGER.debug("Current paging start: {}", pagingStart); + + Integer pagingEnd = getPagingEnd(pagingStart, pagingRemainder, totalPages, i); + + paginated.add(getFilesPathsSplitBySpace(filesWithAbsolutePath, pagingStart, pagingEnd)); + + pagingStart += PAGE_SIZE; + } + return paginated; + } + + private Integer getPagingEnd(Integer pagingStart, Integer pagingRemainder, Integer totalPages, int i) { + Integer pagingEnd = pagingStart + PAGE_SIZE; + if (isLastPage(pagingRemainder, totalPages, i)) { + pagingEnd = pagingStart + pagingRemainder; + } + LOGGER.debug("Current paging end: {}", pagingEnd); + return pagingEnd; + } + + private String getFilesPathsSplitBySpace(List filesWithAbsolutePath, Integer pagingStart, + Integer pagingEnd) { + return filesWithAbsolutePath.subList(pagingStart, pagingEnd).stream().collect(Collectors.joining(" ")); + } + + private boolean isLastPage(Integer pagingRemainder, Integer totalPages, int i) { + return pagingRemainder != 0 && i + 1 == totalPages; + } + + private Integer getPaginationRemainder(List filesWithAbsolutePath) { + Integer remainder = filesWithAbsolutePath.size() % PAGE_SIZE; + + LOGGER.debug("Paging remainder: {}", remainder); + + return remainder; + } + + private Integer getPaginationTotalPages(List filesWithAbsolutePath, final Integer PAGE_SIZE, + Integer remainder) { + Integer total = filesWithAbsolutePath.size() / PAGE_SIZE; + + if (remainder != 0) { + total++; + } + LOGGER.debug("Paging total items: {}", total); + return total; + } + + private List getFilesWithAbsolutePath(SensorContext sensorContext) { + List filesWithAbsolutePath = new ArrayList<>(); + + FileSystem fileSystem = getFileSystem(sensorContext); + + FilePredicate mainFilePredicate = getFilesFilter(fileSystem); + + String absolutePath = fileSystem.baseDir().getAbsolutePath(); + + LOGGER.debug("Files absolute path: {}", absolutePath); + + fileSystem.inputFiles(mainFilePredicate).forEach(s -> { + LOGGER.debug("Input file path: {}", s.toString()); + + String fullPath = new StringBuilder(absolutePath).append(File.separator).append(s.toString().replace("/", File.separator)) + .toString(); + + LOGGER.debug("Current file full path: {}", fullPath); + + filesWithAbsolutePath.add(fullPath); + }); + + return filesWithAbsolutePath; + } + + private FilePredicate getFilesFilter(FileSystem fileSystem) { + FilePredicate mainFilePredicate = fileSystem.predicates().and( + fileSystem.predicates().hasType(InputFile.Type.MAIN), fileSystem.predicates().hasLanguage(Dart.KEY)); + return mainFilePredicate; + } + + private FileSystem getFileSystem(SensorContext sensorContext) { + FileSystem fileSystem = sensorContext.fileSystem(); + return fileSystem; + } + + private void recordIssues(SensorContext sensorContext, List issues) { + // Record issues + issues.forEach(i -> { + File file = new File(sensorContext.fileSystem().baseDir(), i.getFilePath()); + LOGGER.debug("Inside issue forEach, file absolute path: {}", file.getAbsolutePath()); + + FilePredicate fp = sensorContext.fileSystem().predicates().hasAbsolutePath(file.getAbsolutePath()); + if (!sensorContext.fileSystem().hasFiles(fp)) { + LOGGER.warn("File not included in SonarQube {}", file.getAbsoluteFile()); + } else { + InputFile inputFile = sensorContext.fileSystem().inputFile(fp); + NewIssueLocation nil = new DefaultIssueLocation().on(inputFile) + .at(inputFile.selectLine(i.getLineNumber())).message(i.getMessage()); + sensorContext.newIssue().forRule(RuleKey.of(DartAnalyzerRulesDefinition.REPOSITORY_KEY, i.getRuleId())) + .at(nil).save(); + } + }); + } + + private void verifyIfDartAnalyzerExists() { + LOGGER.debug("Verify dart analyser..."); + new ProcBuilder(ANALYZER_COMMAND).withArg("-h").run(); + LOGGER.debug("Verify dart analyser done"); + } + + private boolean existsAnalysisOptionsFile(SensorContext sensorContext) { + return new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME).exists(); + } + + private void saveCurrentAnalysisOptionsFile(SensorContext sensorContext) { + File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); + if (analysisOptionsFile.exists()) { + analysisOptionsFile + .renameTo(new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME + ".sonar")); + LOGGER.info("Backup of original analysis_options.yaml file to {}", ANALYSIS_OPTIONS_FILENAME + ".sonar"); + } + } + + private void createAnalysisOptionsFile(SensorContext sensorContext) throws IOException { + File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); + URL inputUrl = getClass().getResource(ANALYSIS_OPTIONS_FILE); + Resources.asByteSource(inputUrl).copyTo(com.google.common.io.Files.asByteSink(analysisOptionsFile)); + } + + private void restoreCurrentAnalysisOptionsFile(SensorContext sensorContext) { + File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); + File currentAnalysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), + ANALYSIS_OPTIONS_FILENAME + ".sonar"); + if (currentAnalysisOptionsFile.exists()) { + currentAnalysisOptionsFile.renameTo(analysisOptionsFile); + LOGGER.info("Restored original analysis_options.yaml file"); + } else { + analysisOptionsFile.delete(); + } + } } diff --git a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java index 36801cd..6c4b861 100644 --- a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java +++ b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java @@ -77,6 +77,15 @@ public void define(Context context) { .defaultValue("false") .build()); + context.addExtension( + PropertyDefinition.builder(DartSensor.DART_ANALYSIS_USE_EXISTING_REPORT_PATH_KEY) + .name("Use dartanalyzer report file for analysis") + .description("Path to Dartanalyzer report file. If null, dartanalyzer will be executed. The path may be either absolute or relative to the project base directory. Run dartanalyzer with '--write PATH' to create the report.") + .onQualifiers(Qualifiers.MODULE, Qualifiers.PROJECT) + .category(DART_CATEGORY) + .subCategory(ANALYSIS_SUBCATEGORY) + .build()); + // Tests context.addExtension(FlutterTestSensor.class); From da513d8e46650f03fe1e79e5da4ff15b4990d72c Mon Sep 17 00:00:00 2001 From: Daniel Morawetz Date: Sun, 27 Sep 2020 02:56:24 +0200 Subject: [PATCH 04/25] Add pedantic 1.9.0 profile --- .../lang/issues/DartProfilePedantic190.java | 42 +++ .../dart/lang/issues/XmlProfileParser.java | 25 +- .../dartanalyzer/profile-pedantic.1.9.0.xml | 341 ++++++++++++++++++ .../sonarqube/flutter/FlutterPlugin.java | 3 +- 4 files changed, 400 insertions(+), 11 deletions(-) create mode 100644 dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/DartProfilePedantic190.java create mode 100644 dart-lang/src/main/resources/fr/insideapp/sonarqube/dart/dartanalyzer/profile-pedantic.1.9.0.xml diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/DartProfilePedantic190.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/DartProfilePedantic190.java new file mode 100644 index 0000000..03d866d --- /dev/null +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/DartProfilePedantic190.java @@ -0,0 +1,42 @@ +/* + * SonarQube Flutter Plugin + * Copyright (C) 2020 inside|app + * contact@insideapp.fr + * + * 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 fr.insideapp.sonarqube.dart.lang.issues; + +import fr.insideapp.sonarqube.dart.lang.Dart; +import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.DartAnalyzerRulesDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; + +public class DartProfilePedantic190 implements BuiltInQualityProfilesDefinition { + + private static final Logger LOGGER = LoggerFactory.getLogger(DartProfile.class); + public static final String DARTANALYZER_PROFILE_PATH = "fr/insideapp/sonarqube/dart/dartanalyzer/profile-pedantic.1.9.0.xml"; + + @Override + public void define(BuiltInQualityProfilesDefinition.Context context) { + + // dartanalyzer profile + LOGGER.info("Creating dartanalyzer pedantic 1.9.0 Profile"); + NewBuiltInQualityProfile nbiqp = context.createBuiltInQualityProfile("dartanalyzer pedantic 1.9.0", Dart.KEY); + XmlProfileParser.parse(DARTANALYZER_PROFILE_PATH, nbiqp); + nbiqp.done(); + } +} diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/XmlProfileParser.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/XmlProfileParser.java index bc53661..df2e009 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/XmlProfileParser.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/XmlProfileParser.java @@ -48,18 +48,23 @@ public static void parse(String path, NewBuiltInQualityProfile profile) { String repositoryKey = getChildContent(ruleElement, "repositoryKey"); String key = getChildContent(ruleElement, "key"); - NewBuiltInActiveRule newActiveRule = profile.activateRule(repositoryKey, key); + try { + NewBuiltInActiveRule newActiveRule = profile.activateRule(repositoryKey, key); - NodeList parameterNodeList = ruleElement.getElementsByTagName("parameter"); - XmlFile.asList(parameterNodeList).forEach(parameter -> { - Element parameterElement = (Element) parameter; - String paramKey = getChildContent(parameterElement, "key"); - String paramValue = getChildContent(parameterElement, "value"); - newActiveRule.overrideParam(paramKey, paramValue); - }); + NodeList parameterNodeList = ruleElement.getElementsByTagName("parameter"); + XmlFile.asList(parameterNodeList).forEach(parameter -> { + Element parameterElement = (Element) parameter; + String paramKey = getChildContent(parameterElement, "key"); + String paramValue = getChildContent(parameterElement, "value"); + newActiveRule.overrideParam(paramKey, paramValue); + }); - Optional priority = getOptionalChildContent(ruleElement, "priority"); - priority.ifPresent(newActiveRule::overrideSeverity); + Optional priority = getOptionalChildContent(ruleElement, "priority"); + priority.ifPresent(newActiveRule::overrideSeverity); + } catch (IllegalArgumentException e) { + // ignore, if rule was already registered in another profile + } + }); } catch (IOException e) { diff --git a/dart-lang/src/main/resources/fr/insideapp/sonarqube/dart/dartanalyzer/profile-pedantic.1.9.0.xml b/dart-lang/src/main/resources/fr/insideapp/sonarqube/dart/dartanalyzer/profile-pedantic.1.9.0.xml new file mode 100644 index 0000000..c410349 --- /dev/null +++ b/dart-lang/src/main/resources/fr/insideapp/sonarqube/dart/dartanalyzer/profile-pedantic.1.9.0.xml @@ -0,0 +1,341 @@ + + + pedantic 1.9.0 + dart + + + dartanalyzer + always_declare_return_types + + + dartanalyzer + always_require_non_null_named_parameters + + + dartanalyzer + annotate_overrides + + + dartanalyzer + avoid_empty_else + + + dartanalyzer + avoid_init_to_null + + + dartanalyzer + avoid_null_checks_in_equality_operators + + + dartanalyzer + avoid_relative_lib_imports + + + dartanalyzer + avoid_return_types_on_setters + + + dartanalyzer + avoid_shadowing_type_parameters + + + dartanalyzer + avoid_types_as_parameter_names + + + dartanalyzer + camel_case_extensions + + + dartanalyzer + curly_braces_in_flow_control_structures + + + dartanalyzer + empty_catches + + + dartanalyzer + empty_constructor_bodies + + + dartanalyzer + library_names + + + dartanalyzer + library_prefixes + + + dartanalyzer + no_duplicate_case_values + + + dartanalyzer + null_closures + + + dartanalyzer + omit_local_variable_types + + + dartanalyzer + prefer_adjacent_string_concatenation + + + dartanalyzer + prefer_collection_literals + + + dartanalyzer + prefer_conditional_assignment + + + dartanalyzer + prefer_contains + + + dartanalyzer + prefer_equal_for_default_values + + + dartanalyzer + prefer_final_fields + + + dartanalyzer + prefer_for_elements_to_map_fromIterable + + + dartanalyzer + prefer_generic_function_type_aliases + + + dartanalyzer + prefer_if_null_operators + + + dartanalyzer + prefer_is_empty + + + dartanalyzer + prefer_is_not_empty + + + dartanalyzer + prefer_iterable_whereType + + + dartanalyzer + prefer_single_quotes + + + dartanalyzer + prefer_spread_collections + + + dartanalyzer + recursive_getters + + + dartanalyzer + slash_for_doc_comments + + + dartanalyzer + type_init_formals + + + dartanalyzer + unawaited_futures + + + dartanalyzer + unnecessary_const + + + dartanalyzer + unnecessary_new + + + dartanalyzer + unnecessary_null_in_if_null_operators + + + dartanalyzer + unnecessary_this + + + dartanalyzer + unrelated_type_equality_checks + + + dartanalyzer + use_function_type_syntax_for_parameters + + + dartanalyzer + use_rethrow_when_possible + + + dartanalyzer + valid_regexps + + + + dartanalyzer + avoid_returning_null_for_future + + + dartanalyzer + avoid_web_libraries_in_flutter (experimental) + + + dartanalyzer + control_flow_in_finally + + + dartanalyzer + hash_and_equals + + + dartanalyzer + invariant_booleans (experimental) + + + dartanalyzer + iterable_contains_unrelated_type + + + dartanalyzer + list_remove_unrelated_type + + + dartanalyzer + literal_only_boolean_expressions + + + dartanalyzer + no_adjacent_strings_in_list + + + dartanalyzer + no_duplicate_case_values + + + dartanalyzer + test_types_in_equals + + + dartanalyzer + throw_in_finally + + + dartanalyzer + unrelated_type_equality_checks + + + dartanalyzer + use_key_in_widget_constructors + + + dartanalyzer + valid_regexps + + + dartanalyzer + always_require_non_null_named_parameters + + + dartanalyzer + avoid_equals_and_hash_code_on_mutable_classes + + + dartanalyzer + avoid_implementing_value_types + + + dartanalyzer + avoid_js_rounded_ints + + + dartanalyzer + avoid_returning_null + + + dartanalyzer + avoid_returning_null_for_void + + + dartanalyzer + avoid_returning_this + + + dartanalyzer + avoid_void_async + + + dartanalyzer + await_only_futures + + + dartanalyzer + parameter_assignments + + + dartanalyzer + prefer_const_constructors + + + dartanalyzer + prefer_const_constructors_in_immutables + + + dartanalyzer + prefer_const_declarations + + + dartanalyzer + prefer_final_fields + + + dartanalyzer + prefer_final_in_for_each + + + dartanalyzer + prefer_final_locals + + + dartanalyzer + prefer_mixin + + + dartanalyzer + prefer_null_aware_operators + + + dartanalyzer + recursive_getters + + + dartanalyzer + unawaited_futures + + + dartanalyzer + use_full_hex_values_for_flutter_colors + + + dartanalyzer + void_checks + + + + dartanalyzer + unsafe_html + + + \ No newline at end of file diff --git a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java index 36801cd..8593a83 100644 --- a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java +++ b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java @@ -21,6 +21,7 @@ import fr.insideapp.sonarqube.dart.lang.DartSensor; import fr.insideapp.sonarqube.dart.lang.issues.DartProfile; +import fr.insideapp.sonarqube.dart.lang.issues.DartProfilePedantic190; import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.DartAnalyzerRulesDefinition; import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.DartAnalyzerSensor; import fr.insideapp.sonarqube.flutter.coverage.FlutterCoverageSensor; @@ -44,7 +45,7 @@ public class FlutterPlugin implements Plugin { public void define(Context context) { // Language support - context.addExtensions(Dart.class, DartSensor.class, DartProfile.class); + context.addExtensions(Dart.class, DartSensor.class, DartProfile.class, DartProfilePedantic190.class); // dartanalyzer Sensor context.addExtensions(DartAnalyzerSensor.class, DartAnalyzerRulesDefinition.class); From 8dd04a55d1c861173af53e55d3daf2307a591018 Mon Sep 17 00:00:00 2001 From: Daniel Morawetz Date: Sun, 27 Sep 2020 02:59:35 +0200 Subject: [PATCH 05/25] Ensure analyzer encoding is UTF-8 --- .../dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index 1cf7d4e..7a3c8d3 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -113,13 +113,15 @@ private List buildIssues(List filesWithAbsolute LOGGER.debug("Current file batch: {}", paginatedFileBatch); try { - String output = new ProcBuilder(ANALYZER_COMMAND) + byte[] outputBytes = new ProcBuilder(ANALYZER_COMMAND) .withArgs(paginatedFileBatch.split(" ")) .withTimeoutMillis(ANALYZER_TIMEOUT) //.withExpectedExitStatuses(0, 1, 2, 3) .ignoreExitStatus() .run() - .getOutputString(); + .getOutputBytes(); + + String output = new String(outputBytes, "UTF-8"); issues.addAll(new DartAnalyzerReportParser().parse(output)); } catch (Exception e) { From 70ea9227903050f92c157c81658ef9cd039ecd47 Mon Sep 17 00:00:00 2001 From: Franck Terray <49401184+franklychilled@users.noreply.github.com> Date: Wed, 16 Dec 2020 08:36:33 +0000 Subject: [PATCH 06/25] Update README.md Switch flutter test order to provide user feedback when run in Shell script using `set -euo pipefail` --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 87e3acc..0d4aaf6 100644 --- a/README.md +++ b/README.md @@ -84,10 +84,11 @@ Use the following commands from the root folder to start an analysis: ```console # Download dependencies flutter pub get -# Run tests -flutter test --machine > tests.output -# Compute coverage (--machine and --coverage cannot be run at once...) +# Run tests with Compute coverage (--machine and --coverage cannot be run at once...) flutter test --coverage +# Run tests without User feedback +flutter test --machine > tests.output + # Run the analysis and publish to the SonarQube server sonar-scanner ``` From 9dc0f1e64c4023fcd341c95e97a82552b528b0d4 Mon Sep 17 00:00:00 2001 From: Franck Terray <49401184+franklychilled@users.noreply.github.com> Date: Wed, 16 Dec 2020 19:22:56 +0000 Subject: [PATCH 07/25] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0d4aaf6..476c642 100644 --- a/README.md +++ b/README.md @@ -84,10 +84,10 @@ Use the following commands from the root folder to start an analysis: ```console # Download dependencies flutter pub get -# Run tests with Compute coverage (--machine and --coverage cannot be run at once...) -flutter test --coverage -# Run tests without User feedback -flutter test --machine > tests.output +# Run tests with User feedback (in case some test are failing) +flutter test +# Run tests without user feedback regeneration tests.output and coverage/lcov.info +flutter test --machine --coverage > tests.output # Run the analysis and publish to the SonarQube server sonar-scanner From edcc01a2f3aefcde871eaa78d03a6a94e12f6d99 Mon Sep 17 00:00:00 2001 From: Marc Reichelt Date: Thu, 4 Mar 2021 14:48:07 +0100 Subject: [PATCH 08/25] Add Flutter command --- .../issues/dartanalyzer/DartAnalyzerSensor.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index 1cf7d4e..f427e2d 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -48,15 +48,18 @@ public class DartAnalyzerSensor implements Sensor { private static final Logger LOGGER = LoggerFactory.getLogger(DartAnalyzerSensor.class); - private static final String ANALYZER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") + private static final String ANALYZER_DART_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") ? "dartanalyzer.bat" : "dartanalyzer"; + private static final String ANALYZER_FLUTTER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") + ? "flutter.bat" + : "flutter"; private static final int ANALYZER_TIMEOUT = 10 * 60 * 1000; private static final String ANALYSIS_OPTIONS_FILENAME = "analysis_options.yaml"; private static final String ANALYSIS_OPTIONS_FILE = "/fr/insideapp/sonarqube/dart/dartanalyzer/analysis_options.yaml"; private static final Integer PAGE_SIZE = 50; private boolean useExistingAnalysisOptions; - + @Override public void describe(SensorDescriptor sensorDescriptor) { sensorDescriptor.onlyOnLanguage(Dart.KEY).name("dartanalyzer sensor").onlyOnFileType(Type.MAIN); @@ -66,7 +69,7 @@ public void describe(SensorDescriptor sensorDescriptor) { public void execute(SensorContext sensorContext) { try { verifyIfDartAnalyzerExists(); - + selectOptionFileToUse(sensorContext); recordIssues(sensorContext, buildIssues(getFilesWithAbsolutePath(sensorContext))); @@ -113,7 +116,7 @@ private List buildIssues(List filesWithAbsolute LOGGER.debug("Current file batch: {}", paginatedFileBatch); try { - String output = new ProcBuilder(ANALYZER_COMMAND) + String output = new ProcBuilder(ANALYZER_DART_COMMAND) .withArgs(paginatedFileBatch.split(" ")) .withTimeoutMillis(ANALYZER_TIMEOUT) //.withExpectedExitStatuses(0, 1, 2, 3) @@ -251,7 +254,7 @@ private void recordIssues(SensorContext sensorContext, List Date: Thu, 4 Mar 2021 15:31:19 +0100 Subject: [PATCH 09/25] Add test for example Flutter report --- .../DartAnalyzerReportParserTest.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/dart-lang/src/test/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerReportParserTest.java b/dart-lang/src/test/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerReportParserTest.java index 9fdf87b..4c8eb09 100644 --- a/dart-lang/src/test/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerReportParserTest.java +++ b/dart-lang/src/test/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerReportParserTest.java @@ -19,11 +19,11 @@ */ package fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; import java.util.List; -import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; public class DartAnalyzerReportParserTest { @@ -89,7 +89,24 @@ public void parseWithTraces() { assertRuleId(issues.get(10), RULE_ID_UNUSED_LOCAL_VARIABLE); assertMessage(issues.get(10), "The value of the local variable 'j' isn't used."); } - + + @Test + public void parseFlutterReport() { + String input = " info • The value of the local variable 'chocolate' isn't used • lib/api/icecream/icecream_api.dart:110:29 • unused_local_variable\n" + + " info • 'nothing' is deprecated and shouldn't be used. Do not use this anymore, please use [Nothing] instead. • lib/src/path/to/very_cool_widget.dart:32:59 • deprecated_member_use_from_same_package\n" + + " info • The parameter 'foo' is required • lib/src/path/to/this_file.dart:9:5 • missing_required_param\n" + + " info • Unnecessary await keyword in return • lib/path/to/other/file.dart:37:27 • unnecessary_await_in_return"; + + List issues = parser.parse(input); + assertThat(issues).hasSize(4); + assertThat(issues.stream().map(DartAnalyzerReportIssue::getRuleId)).containsExactly( + "unused_local_variable", + "deprecated_member_use_from_same_package", + "missing_required_param", + "unnecessary_await_in_return" + ); + } + private void assertFilePath(DartAnalyzerReportIssue issue, String expectedPath) { assertThat(issue.getFilePath()).isEqualTo(expectedPath); } From c4a0be9e5301a9203fc830c9ae23fc882ab5aab4 Mon Sep 17 00:00:00 2001 From: Marc Reichelt Date: Thu, 4 Mar 2021 15:43:03 +0100 Subject: [PATCH 10/25] Parse Flutter reports correctly --- .../dart/lang/issues/dartanalyzer/DartAnalyzerReportParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerReportParser.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerReportParser.java index db0027b..176ee4a 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerReportParser.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerReportParser.java @@ -31,7 +31,7 @@ public List parse(String input) { List issues = new ArrayList<>(); String[] lines = input.split(System.getProperty("line.separator")); - Pattern pattern = Pattern.compile("(error|hint|lint)(.*)(-|•)(.*)(-|•)(.*):(.*):(.*)(-|•)(.*)"); + Pattern pattern = Pattern.compile("(hint|lint|info|warning|error)(.*)(-|•)(.*)(-|•)(.*):(.*):(.*)(-|•)(.*)"); for (int i = 0; i < lines.length; i++) { Matcher matcher = pattern.matcher(lines[i]); while (matcher.find()) { From 1646f23ce696a1b215d7d76d0e724ccc1d6990bb Mon Sep 17 00:00:00 2001 From: Marc Reichelt Date: Fri, 5 Mar 2021 11:41:36 +0100 Subject: [PATCH 11/25] Add option to run `flutter analyze` - much faster than before - setting legacy/flutter enables projects to opt-in to new mode - until we can safely auto-detect everything --- .../issues/dartanalyzer/AnalyzerMode.java | 26 + .../dartanalyzer/DartAnalyzerSensor.java | 523 ++++++++++-------- .../sonarqube/flutter/FlutterPlugin.java | 18 +- 3 files changed, 327 insertions(+), 240 deletions(-) create mode 100644 dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java new file mode 100644 index 0000000..9ec535a --- /dev/null +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java @@ -0,0 +1,26 @@ +/* + * SonarQube Flutter Plugin + * Copyright (C) 2020 inside|app + * contact@insideapp.fr + * + * 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 fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer; + +public enum AnalyzerMode { + legacy, + flutter, +} diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index f427e2d..b0c1680 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -46,246 +46,293 @@ import java.util.Set; import java.util.stream.Collectors; -public class DartAnalyzerSensor implements Sensor { - private static final Logger LOGGER = LoggerFactory.getLogger(DartAnalyzerSensor.class); - private static final String ANALYZER_DART_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") - ? "dartanalyzer.bat" - : "dartanalyzer"; - private static final String ANALYZER_FLUTTER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") - ? "flutter.bat" - : "flutter"; - private static final int ANALYZER_TIMEOUT = 10 * 60 * 1000; - private static final String ANALYSIS_OPTIONS_FILENAME = "analysis_options.yaml"; - private static final String ANALYSIS_OPTIONS_FILE = "/fr/insideapp/sonarqube/dart/dartanalyzer/analysis_options.yaml"; - private static final Integer PAGE_SIZE = 50; - private boolean useExistingAnalysisOptions; - - @Override - public void describe(SensorDescriptor sensorDescriptor) { - sensorDescriptor.onlyOnLanguage(Dart.KEY).name("dartanalyzer sensor").onlyOnFileType(Type.MAIN); - } - - @Override - public void execute(SensorContext sensorContext) { - try { - verifyIfDartAnalyzerExists(); - - selectOptionFileToUse(sensorContext); - - recordIssues(sensorContext, buildIssues(getFilesWithAbsolutePath(sensorContext))); - - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } finally { - if (!useExistingAnalysisOptions) { - restoreCurrentAnalysisOptionsFile(sensorContext); - } - } - } - - private void selectOptionFileToUse(SensorContext sensorContext) throws IOException { - useExistingAnalysisOptions = getUseExistingAnalysisOptions(sensorContext); - - // Usage of existing option is required but file is missing - // Or usage of existing option is not required - if ((useExistingAnalysisOptions && !this.existsAnalysisOptionsFile(sensorContext)) || !useExistingAnalysisOptions) { - useDefaultAnalysisOptionsFile(sensorContext); - } - } - - private void useDefaultAnalysisOptionsFile(SensorContext sensorContext) throws IOException { - LOGGER.debug("Either {} option is not set to true or {} file does not exists, use default analysis options instead", - DartSensor.DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY, ANALYSIS_OPTIONS_FILENAME); - - useExistingAnalysisOptions = false; - - this.saveCurrentAnalysisOptionsFile(sensorContext); - this.createAnalysisOptionsFile(sensorContext); - } - - private Boolean getUseExistingAnalysisOptions(SensorContext sensorContext) { - return sensorContext.config().getBoolean(DartSensor.DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY).orElse(false); - } - - private List buildIssues(List filesWithAbsolutePath) - throws IOException { - Set issues = new HashSet<>(); - - for (String paginatedFileBatch : getPaginatedFilesPaths(filesWithAbsolutePath)) { - - LOGGER.debug("Current file batch: {}", paginatedFileBatch); - - try { - String output = new ProcBuilder(ANALYZER_DART_COMMAND) - .withArgs(paginatedFileBatch.split(" ")) - .withTimeoutMillis(ANALYZER_TIMEOUT) - //.withExpectedExitStatuses(0, 1, 2, 3) - .ignoreExitStatus() - .run() - .getOutputString(); +import static java.util.Arrays.asList; - issues.addAll(new DartAnalyzerReportParser().parse(output)); - } catch (Exception e) { - throw new IOException(e); - } +public class DartAnalyzerSensor implements Sensor { + private static final Logger LOGGER = LoggerFactory.getLogger(DartAnalyzerSensor.class); + private static final String ANALYZER_DART_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") + ? "dartanalyzer.bat" + : "dartanalyzer"; + private static final String ANALYZER_FLUTTER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") + ? "flutter.bat" + : "flutter"; + private static final int ANALYZER_TIMEOUT = 10 * 60 * 1000; + private static final String ANALYSIS_OPTIONS_FILENAME = "analysis_options.yaml"; + private static final String ANALYSIS_OPTIONS_FILE = "/fr/insideapp/sonarqube/dart/dartanalyzer/analysis_options.yaml"; + private static final Integer PAGE_SIZE = 50; + private boolean useExistingAnalysisOptions; + public static final String FLUTTER_ANALYZER_MODE = "sonar.flutter.analyzer.mode"; + public static final List FLUTTER_ANALYZER_MODE_OPTIONS = asList(AnalyzerMode.values()); + + @Override + public void describe(SensorDescriptor sensorDescriptor) { + sensorDescriptor.onlyOnLanguage(Dart.KEY).name("dartanalyzer sensor").onlyOnFileType(Type.MAIN); + } + + @Override + public void execute(SensorContext sensorContext) { + + AnalyzerMode analyzerMode = getAnalyzerMode(sensorContext); + LOGGER.info("Chosen analyzer mode: {}", analyzerMode); + + switch (analyzerMode) { + case legacy: + try { + + verifyIfDartAnalyzerExists(); + + selectOptionFileToUse(sensorContext); + + recordIssues(sensorContext, buildIssues(getFilesWithAbsolutePath(sensorContext))); + + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + if (!useExistingAnalysisOptions) { + restoreCurrentAnalysisOptionsFile(sensorContext); + } + } + break; + + case flutter: + try { + final List issues = getIssuesFromFlutterAnalyze(); + recordIssues(sensorContext, issues); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + break; + } + } + + private List getIssuesFromFlutterAnalyze() throws IOException { + try { + LOGGER.info("Running 'flutter analyze'..."); + String output = new ProcBuilder(ANALYZER_FLUTTER_COMMAND, "analyze") + .withTimeoutMillis(ANALYZER_TIMEOUT) + .ignoreExitStatus() + .run() + .getOutputString(); + + List issues = new DartAnalyzerReportParser().parse(output); + LOGGER.info("Found issues: {}", issues.size()); + return issues; + } catch (Exception e) { + throw new IOException(e); + } + } + + private void selectOptionFileToUse(SensorContext sensorContext) throws IOException { + useExistingAnalysisOptions = getUseExistingAnalysisOptions(sensorContext); + + // Usage of existing option is required but file is missing + // Or usage of existing option is not required + if ((useExistingAnalysisOptions && !this.existsAnalysisOptionsFile(sensorContext)) || !useExistingAnalysisOptions) { + useDefaultAnalysisOptionsFile(sensorContext); + } + } + + private void useDefaultAnalysisOptionsFile(SensorContext sensorContext) throws IOException { + LOGGER.debug("Either {} option is not set to true or {} file does not exists, use default analysis options instead", + DartSensor.DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY, ANALYSIS_OPTIONS_FILENAME); + + useExistingAnalysisOptions = false; + + this.saveCurrentAnalysisOptionsFile(sensorContext); + this.createAnalysisOptionsFile(sensorContext); + } + + private AnalyzerMode getAnalyzerMode(SensorContext sensorContext) { + return sensorContext.config() + .get(FLUTTER_ANALYZER_MODE) + .map(AnalyzerMode::valueOf) + .orElse(AnalyzerMode.legacy); + } + + private Boolean getUseExistingAnalysisOptions(SensorContext sensorContext) { + return sensorContext.config().getBoolean(DartSensor.DART_ANALYSIS_USE_EXISTING_OPTIONS_KEY).orElse(false); + } + + private List buildIssues(List filesWithAbsolutePath) + throws IOException { + Set issues = new HashSet<>(); + + for (String paginatedFileBatch : getPaginatedFilesPaths(filesWithAbsolutePath)) { + + LOGGER.debug("Current file batch: {}", paginatedFileBatch); + + try { + String output = new ProcBuilder(ANALYZER_DART_COMMAND) + .withArgs(paginatedFileBatch.split(" ")) + .withTimeoutMillis(ANALYZER_TIMEOUT) + //.withExpectedExitStatuses(0, 1, 2, 3) + .ignoreExitStatus() + .run() + .getOutputString(); - } - LOGGER.debug("Found issues: {}", issues.size()); - List result = new ArrayList<>(); - result.addAll(issues); - return result; - } - - private List getPaginatedFilesPaths(List filesWithAbsolutePath) { - List paginated = new ArrayList(); - - LOGGER.debug("Paging the files to execute the analyzer..."); - - Integer pagingStart = 0; - Integer pagingRemainder = getPaginationRemainder(filesWithAbsolutePath); - Integer totalPages = getPaginationTotalPages(filesWithAbsolutePath, PAGE_SIZE, pagingRemainder); - - for (int i = 0; i < totalPages; i++) { - LOGGER.debug("Current index: {}", i); - - LOGGER.debug("Current paging start: {}", pagingStart); - - Integer pagingEnd = getPagingEnd(pagingStart, pagingRemainder, totalPages, i); - - paginated.add(getFilesPathsSplitBySpace(filesWithAbsolutePath, pagingStart, pagingEnd)); - - pagingStart += PAGE_SIZE; - } - return paginated; - } + issues.addAll(new DartAnalyzerReportParser().parse(output)); + } catch (Exception e) { + throw new IOException(e); + } - private Integer getPagingEnd(Integer pagingStart, Integer pagingRemainder, Integer totalPages, int i) { - Integer pagingEnd = pagingStart + PAGE_SIZE; - if (isLastPage(pagingRemainder, totalPages, i)) { - pagingEnd = pagingStart + pagingRemainder; - } - LOGGER.debug("Current paging end: {}", pagingEnd); - return pagingEnd; - } - - private String getFilesPathsSplitBySpace(List filesWithAbsolutePath, Integer pagingStart, - Integer pagingEnd) { - return filesWithAbsolutePath.subList(pagingStart, pagingEnd).stream().collect(Collectors.joining(" ")); - } - - private boolean isLastPage(Integer pagingRemainder, Integer totalPages, int i) { - return pagingRemainder != 0 && i + 1 == totalPages; - } - - private Integer getPaginationRemainder(List filesWithAbsolutePath) { - Integer remainder = filesWithAbsolutePath.size() % PAGE_SIZE; - - LOGGER.debug("Paging remainder: {}", remainder); - - return remainder; - } - - private Integer getPaginationTotalPages(List filesWithAbsolutePath, final Integer PAGE_SIZE, - Integer remainder) { - Integer total = filesWithAbsolutePath.size() / PAGE_SIZE; - - if (remainder != 0) { - total++; - } - LOGGER.debug("Paging total items: {}", total); - return total; - } - - private List getFilesWithAbsolutePath(SensorContext sensorContext) { - List filesWithAbsolutePath = new ArrayList<>(); - - FileSystem fileSystem = getFileSystem(sensorContext); - - FilePredicate mainFilePredicate = getFilesFilter(fileSystem); - - String absolutePath = fileSystem.baseDir().getAbsolutePath(); - - LOGGER.debug("Files absolute path: {}", absolutePath); - - fileSystem.inputFiles(mainFilePredicate).forEach(s -> { - LOGGER.debug("Input file path: {}", s.toString()); - - String fullPath = new StringBuilder(absolutePath).append(File.separator).append(s.toString().replace("/", File.separator)) - .toString(); - - LOGGER.debug("Current file full path: {}", fullPath); - - filesWithAbsolutePath.add(fullPath); - }); - - return filesWithAbsolutePath; - } - - private FilePredicate getFilesFilter(FileSystem fileSystem) { - FilePredicate mainFilePredicate = fileSystem.predicates().and( - fileSystem.predicates().hasType(InputFile.Type.MAIN), fileSystem.predicates().hasLanguage(Dart.KEY)); - return mainFilePredicate; - } - - private FileSystem getFileSystem(SensorContext sensorContext) { - FileSystem fileSystem = sensorContext.fileSystem(); - return fileSystem; - } - - private void recordIssues(SensorContext sensorContext, List issues) { - // Record issues - issues.forEach(i -> { - File file = new File(sensorContext.fileSystem().baseDir(), i.getFilePath()); - LOGGER.debug("Inside issue forEach, file absolute path: {}", file.getAbsolutePath()); - - FilePredicate fp = sensorContext.fileSystem().predicates().hasAbsolutePath(file.getAbsolutePath()); - if (!sensorContext.fileSystem().hasFiles(fp)) { - LOGGER.warn("File not included in SonarQube {}", file.getAbsoluteFile()); - } else { - InputFile inputFile = sensorContext.fileSystem().inputFile(fp); - NewIssueLocation nil = new DefaultIssueLocation().on(inputFile) - .at(inputFile.selectLine(i.getLineNumber())).message(i.getMessage()); - sensorContext.newIssue().forRule(RuleKey.of(DartAnalyzerRulesDefinition.REPOSITORY_KEY, i.getRuleId())) - .at(nil).save(); - } - }); - } - - private void verifyIfDartAnalyzerExists() { - LOGGER.debug("Verify dart analyser..."); - new ProcBuilder(ANALYZER_DART_COMMAND).withArg("-h").run(); - LOGGER.debug("Verify dart analyser done"); - } - - private boolean existsAnalysisOptionsFile(SensorContext sensorContext) { - return new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME).exists(); - } - - private void saveCurrentAnalysisOptionsFile(SensorContext sensorContext) { - File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); - if (analysisOptionsFile.exists()) { - analysisOptionsFile - .renameTo(new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME + ".sonar")); - LOGGER.info("Backup of original analysis_options.yaml file to {}", ANALYSIS_OPTIONS_FILENAME + ".sonar"); - } - } - - private void createAnalysisOptionsFile(SensorContext sensorContext) throws IOException { - File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); - URL inputUrl = getClass().getResource(ANALYSIS_OPTIONS_FILE); - Resources.asByteSource(inputUrl).copyTo(Files.asByteSink(analysisOptionsFile)); - } - - private void restoreCurrentAnalysisOptionsFile(SensorContext sensorContext) { - File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); - File currentAnalysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), - ANALYSIS_OPTIONS_FILENAME + ".sonar"); - if (currentAnalysisOptionsFile.exists()) { - currentAnalysisOptionsFile.renameTo(analysisOptionsFile); - LOGGER.info("Restored original analysis_options.yaml file"); - } else { - analysisOptionsFile.delete(); - } - } + + } + LOGGER.debug("Found issues: {}", issues.size()); + List result = new ArrayList<>(); + result.addAll(issues); + return result; + } + + private List getPaginatedFilesPaths(List filesWithAbsolutePath) { + List paginated = new ArrayList(); + + LOGGER.debug("Paging the files to execute the analyzer..."); + + Integer pagingStart = 0; + Integer pagingRemainder = getPaginationRemainder(filesWithAbsolutePath); + Integer totalPages = getPaginationTotalPages(filesWithAbsolutePath, PAGE_SIZE, pagingRemainder); + + for (int i = 0; i < totalPages; i++) { + LOGGER.debug("Current index: {}", i); + + LOGGER.debug("Current paging start: {}", pagingStart); + + Integer pagingEnd = getPagingEnd(pagingStart, pagingRemainder, totalPages, i); + + paginated.add(getFilesPathsSplitBySpace(filesWithAbsolutePath, pagingStart, pagingEnd)); + + pagingStart += PAGE_SIZE; + } + return paginated; + } + + private Integer getPagingEnd(Integer pagingStart, Integer pagingRemainder, Integer totalPages, int i) { + Integer pagingEnd = pagingStart + PAGE_SIZE; + if (isLastPage(pagingRemainder, totalPages, i)) { + pagingEnd = pagingStart + pagingRemainder; + } + LOGGER.debug("Current paging end: {}", pagingEnd); + return pagingEnd; + } + + private String getFilesPathsSplitBySpace(List filesWithAbsolutePath, Integer pagingStart, + Integer pagingEnd) { + return filesWithAbsolutePath.subList(pagingStart, pagingEnd).stream().collect(Collectors.joining(" ")); + } + + private boolean isLastPage(Integer pagingRemainder, Integer totalPages, int i) { + return pagingRemainder != 0 && i + 1 == totalPages; + } + + private Integer getPaginationRemainder(List filesWithAbsolutePath) { + Integer remainder = filesWithAbsolutePath.size() % PAGE_SIZE; + + LOGGER.debug("Paging remainder: {}", remainder); + + return remainder; + } + + private Integer getPaginationTotalPages(List filesWithAbsolutePath, final Integer PAGE_SIZE, + Integer remainder) { + Integer total = filesWithAbsolutePath.size() / PAGE_SIZE; + + if (remainder != 0) { + total++; + } + LOGGER.debug("Paging total items: {}", total); + return total; + } + + private List getFilesWithAbsolutePath(SensorContext sensorContext) { + List filesWithAbsolutePath = new ArrayList<>(); + + FileSystem fileSystem = getFileSystem(sensorContext); + + FilePredicate mainFilePredicate = getFilesFilter(fileSystem); + + String absolutePath = fileSystem.baseDir().getAbsolutePath(); + + LOGGER.debug("Files absolute path: {}", absolutePath); + + fileSystem.inputFiles(mainFilePredicate).forEach(s -> { + LOGGER.debug("Input file path: {}", s.toString()); + + String fullPath = new StringBuilder(absolutePath).append(File.separator).append(s.toString().replace("/", File.separator)) + .toString(); + + LOGGER.debug("Current file full path: {}", fullPath); + + filesWithAbsolutePath.add(fullPath); + }); + + return filesWithAbsolutePath; + } + + private FilePredicate getFilesFilter(FileSystem fileSystem) { + FilePredicate mainFilePredicate = fileSystem.predicates().and( + fileSystem.predicates().hasType(InputFile.Type.MAIN), fileSystem.predicates().hasLanguage(Dart.KEY)); + return mainFilePredicate; + } + + private FileSystem getFileSystem(SensorContext sensorContext) { + FileSystem fileSystem = sensorContext.fileSystem(); + return fileSystem; + } + + private void recordIssues(SensorContext sensorContext, List issues) { + // Record issues + issues.forEach(i -> { + File file = new File(sensorContext.fileSystem().baseDir(), i.getFilePath()); + LOGGER.debug("Inside issue forEach, file absolute path: {}", file.getAbsolutePath()); + + FilePredicate fp = sensorContext.fileSystem().predicates().hasAbsolutePath(file.getAbsolutePath()); + if (!sensorContext.fileSystem().hasFiles(fp)) { + LOGGER.warn("File not included in SonarQube {}", file.getAbsoluteFile()); + } else { + InputFile inputFile = sensorContext.fileSystem().inputFile(fp); + NewIssueLocation nil = new DefaultIssueLocation().on(inputFile) + .at(inputFile.selectLine(i.getLineNumber())).message(i.getMessage()); + sensorContext.newIssue().forRule(RuleKey.of(DartAnalyzerRulesDefinition.REPOSITORY_KEY, i.getRuleId())) + .at(nil).save(); + } + }); + } + + private void verifyIfDartAnalyzerExists() { + LOGGER.debug("Verify dart analyser..."); + new ProcBuilder(ANALYZER_DART_COMMAND).withArg("-h").run(); + LOGGER.debug("Verify dart analyser done"); + } + + private boolean existsAnalysisOptionsFile(SensorContext sensorContext) { + return new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME).exists(); + } + + private void saveCurrentAnalysisOptionsFile(SensorContext sensorContext) { + File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); + if (analysisOptionsFile.exists()) { + analysisOptionsFile + .renameTo(new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME + ".sonar")); + LOGGER.info("Backup of original analysis_options.yaml file to {}", ANALYSIS_OPTIONS_FILENAME + ".sonar"); + } + } + + private void createAnalysisOptionsFile(SensorContext sensorContext) throws IOException { + File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); + URL inputUrl = getClass().getResource(ANALYSIS_OPTIONS_FILE); + Resources.asByteSource(inputUrl).copyTo(Files.asByteSink(analysisOptionsFile)); + } + + private void restoreCurrentAnalysisOptionsFile(SensorContext sensorContext) { + File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); + File currentAnalysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), + ANALYSIS_OPTIONS_FILENAME + ".sonar"); + if (currentAnalysisOptionsFile.exists()) { + currentAnalysisOptionsFile.renameTo(analysisOptionsFile); + LOGGER.info("Restored original analysis_options.yaml file"); + } else { + analysisOptionsFile.delete(); + } + } } diff --git a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java index 36801cd..7f43191 100644 --- a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java +++ b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java @@ -19,6 +19,7 @@ */ package fr.insideapp.sonarqube.flutter; +import fr.insideapp.sonarqube.dart.lang.Dart; import fr.insideapp.sonarqube.dart.lang.DartSensor; import fr.insideapp.sonarqube.dart.lang.issues.DartProfile; import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.DartAnalyzerRulesDefinition; @@ -26,16 +27,17 @@ import fr.insideapp.sonarqube.flutter.coverage.FlutterCoverageSensor; import fr.insideapp.sonarqube.flutter.tests.FlutterTestSensor; import org.sonar.api.Plugin; -import fr.insideapp.sonarqube.dart.lang.Dart; +import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.resources.Qualifiers; +import java.util.stream.Collectors; + public class FlutterPlugin implements Plugin { public static final String DART_CATEGORY = "Dart"; public static final String FLUTTER_CATEGORY = "Flutter"; public static final String ANALYSIS_SUBCATEGORY = "Analysis"; - public static final String GENERAL_SUBCATEGORY = "General"; public static final String TESTS_SUBCATEGORY = "Tests"; public static final String FLUTTER_TESTS_REPORT_PATH_KEY = "sonar.flutter.tests.reportPath"; @@ -77,6 +79,18 @@ public void define(Context context) { .defaultValue("false") .build()); + context.addExtension( + PropertyDefinition.builder(DartAnalyzerSensor.FLUTTER_ANALYZER_MODE) + .name("Analyzer") + .description("Which analyzer to use") + .onQualifiers(Qualifiers.MODULE, Qualifiers.PROJECT) + .category(DART_CATEGORY) + .subCategory(ANALYSIS_SUBCATEGORY) + .options(DartAnalyzerSensor.FLUTTER_ANALYZER_MODE_OPTIONS.stream().map(Enum::name).collect(Collectors.toList())) + .defaultValue(DartAnalyzerSensor.FLUTTER_ANALYZER_MODE_OPTIONS.get(0).name()) + .type(PropertyType.SINGLE_SELECT_LIST) + .build()); + // Tests context.addExtension(FlutterTestSensor.class); From 8793ca8d7fb2143dffd3b2991031c526f7ea0537 Mon Sep 17 00:00:00 2001 From: Marc Reichelt Date: Thu, 1 Apr 2021 14:40:03 +0200 Subject: [PATCH 12/25] Set default to `flutter analyze` - because it is much faster :-) - and it also works on pure Dart projects! --- .../dart/lang/issues/dartanalyzer/AnalyzerMode.java | 2 +- .../lang/issues/dartanalyzer/DartAnalyzerSensor.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java index 9ec535a..8812778 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java @@ -21,6 +21,6 @@ package fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer; public enum AnalyzerMode { - legacy, flutter, + legacy, } diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index b0c1680..e81aff7 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -51,10 +51,10 @@ public class DartAnalyzerSensor implements Sensor { private static final Logger LOGGER = LoggerFactory.getLogger(DartAnalyzerSensor.class); - private static final String ANALYZER_DART_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") + private static final String LEGACY_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") ? "dartanalyzer.bat" : "dartanalyzer"; - private static final String ANALYZER_FLUTTER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") + private static final String FLUTTER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") ? "flutter.bat" : "flutter"; private static final int ANALYZER_TIMEOUT = 10 * 60 * 1000; @@ -109,7 +109,7 @@ public void execute(SensorContext sensorContext) { private List getIssuesFromFlutterAnalyze() throws IOException { try { LOGGER.info("Running 'flutter analyze'..."); - String output = new ProcBuilder(ANALYZER_FLUTTER_COMMAND, "analyze") + String output = new ProcBuilder(FLUTTER_COMMAND, "analyze") .withTimeoutMillis(ANALYZER_TIMEOUT) .ignoreExitStatus() .run() @@ -147,7 +147,7 @@ private AnalyzerMode getAnalyzerMode(SensorContext sensorContext) { return sensorContext.config() .get(FLUTTER_ANALYZER_MODE) .map(AnalyzerMode::valueOf) - .orElse(AnalyzerMode.legacy); + .orElse(AnalyzerMode.flutter); } private Boolean getUseExistingAnalysisOptions(SensorContext sensorContext) { @@ -163,7 +163,7 @@ private List buildIssues(List filesWithAbsolute LOGGER.debug("Current file batch: {}", paginatedFileBatch); try { - String output = new ProcBuilder(ANALYZER_DART_COMMAND) + String output = new ProcBuilder(LEGACY_COMMAND) .withArgs(paginatedFileBatch.split(" ")) .withTimeoutMillis(ANALYZER_TIMEOUT) //.withExpectedExitStatuses(0, 1, 2, 3) @@ -301,7 +301,7 @@ private void recordIssues(SensorContext sensorContext, List Date: Thu, 1 Apr 2021 14:57:06 +0200 Subject: [PATCH 13/25] Improve code for setting the default --- .../sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java | 4 +++- .../dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java | 2 +- .../java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java index 8812778..0c388e9 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java @@ -22,5 +22,7 @@ public enum AnalyzerMode { flutter, - legacy, + legacy; + + public static final AnalyzerMode defaultMode = flutter; } diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index e81aff7..01bb743 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -147,7 +147,7 @@ private AnalyzerMode getAnalyzerMode(SensorContext sensorContext) { return sensorContext.config() .get(FLUTTER_ANALYZER_MODE) .map(AnalyzerMode::valueOf) - .orElse(AnalyzerMode.flutter); + .orElse(AnalyzerMode.defaultMode); } private Boolean getUseExistingAnalysisOptions(SensorContext sensorContext) { diff --git a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java index 7f43191..c4f9f28 100644 --- a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java +++ b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java @@ -22,6 +22,7 @@ import fr.insideapp.sonarqube.dart.lang.Dart; import fr.insideapp.sonarqube.dart.lang.DartSensor; import fr.insideapp.sonarqube.dart.lang.issues.DartProfile; +import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.AnalyzerMode; import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.DartAnalyzerRulesDefinition; import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.DartAnalyzerSensor; import fr.insideapp.sonarqube.flutter.coverage.FlutterCoverageSensor; @@ -87,7 +88,7 @@ public void define(Context context) { .category(DART_CATEGORY) .subCategory(ANALYSIS_SUBCATEGORY) .options(DartAnalyzerSensor.FLUTTER_ANALYZER_MODE_OPTIONS.stream().map(Enum::name).collect(Collectors.toList())) - .defaultValue(DartAnalyzerSensor.FLUTTER_ANALYZER_MODE_OPTIONS.get(0).name()) + .defaultValue(AnalyzerMode.defaultMode.name()) .type(PropertyType.SINGLE_SELECT_LIST) .build()); From e94d4047ecb70b28f59c95c837cbcec2051b600f Mon Sep 17 00:00:00 2001 From: Marc Reichelt Date: Thu, 1 Apr 2021 16:49:14 +0200 Subject: [PATCH 14/25] Add possibility to run `dart analyze` - also: new option to set that on each project level --- .../issues/dartanalyzer/AnalyzerMode.java | 1 + .../dartanalyzer/DartAnalyzerSensor.java | 33 ++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java index 0c388e9..4f271d0 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/AnalyzerMode.java @@ -22,6 +22,7 @@ public enum AnalyzerMode { flutter, + dart, legacy; public static final AnalyzerMode defaultMode = flutter; diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index 01bb743..72fde81 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -23,6 +23,7 @@ import com.google.common.io.Resources; import fr.insideapp.sonarqube.dart.lang.Dart; import fr.insideapp.sonarqube.dart.lang.DartSensor; +import org.apache.commons.lang.NotImplementedException; import org.buildobjects.process.ProcBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,6 +58,9 @@ public class DartAnalyzerSensor implements Sensor { private static final String FLUTTER_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") ? "flutter.bat" : "flutter"; + private static final String DART_COMMAND = System.getProperty("os.name").toUpperCase().contains("WINDOWS") + ? "dart.bat" + : "dart"; private static final int ANALYZER_TIMEOUT = 10 * 60 * 1000; private static final String ANALYSIS_OPTIONS_FILENAME = "analysis_options.yaml"; private static final String ANALYSIS_OPTIONS_FILE = "/fr/insideapp/sonarqube/dart/dartanalyzer/analysis_options.yaml"; @@ -96,20 +100,31 @@ public void execute(SensorContext sensorContext) { break; case flutter: - try { - final List issues = getIssuesFromFlutterAnalyze(); - recordIssues(sensorContext, issues); - } catch (Exception e) { - LOGGER.error(e.getMessage(), e); - } + recordIssuesFromAnalyzer(sensorContext, FLUTTER_COMMAND); + break; + + case dart: + recordIssuesFromAnalyzer(sensorContext, DART_COMMAND); break; + + default: + throw new NotImplementedException(); + } + } + + private void recordIssuesFromAnalyzer(SensorContext sensorContext, String analyzerCommand) { + try { + final List issues = getIssuesFromAnalyzer(analyzerCommand); + recordIssues(sensorContext, issues); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); } } - private List getIssuesFromFlutterAnalyze() throws IOException { + private List getIssuesFromAnalyzer(String analyzerCommand) throws IOException { try { - LOGGER.info("Running 'flutter analyze'..."); - String output = new ProcBuilder(FLUTTER_COMMAND, "analyze") + LOGGER.info("Running '{} analyze'...", analyzerCommand); + String output = new ProcBuilder(analyzerCommand, "analyze") .withTimeoutMillis(ANALYZER_TIMEOUT) .ignoreExitStatus() .run() From 85121127b1cbd823b60692e49b43167f8f9be23c Mon Sep 17 00:00:00 2001 From: Marc Reichelt Date: Fri, 16 Apr 2021 18:23:55 +0200 Subject: [PATCH 15/25] Use absolute class to avoid potential issues --- .../dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index 72fde81..2fb2503 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -335,7 +335,7 @@ private void saveCurrentAnalysisOptionsFile(SensorContext sensorContext) { private void createAnalysisOptionsFile(SensorContext sensorContext) throws IOException { File analysisOptionsFile = new File(sensorContext.fileSystem().baseDir(), ANALYSIS_OPTIONS_FILENAME); - URL inputUrl = getClass().getResource(ANALYSIS_OPTIONS_FILE); + URL inputUrl = DartAnalyzerSensor.class.getResource(ANALYSIS_OPTIONS_FILE); Resources.asByteSource(inputUrl).copyTo(Files.asByteSink(analysisOptionsFile)); } From 777d51b2ebdf09d29b46c45c809297ee36bd07ea Mon Sep 17 00:00:00 2001 From: Peter Leibiger Date: Fri, 23 Apr 2021 13:02:41 +0200 Subject: [PATCH 16/25] Add required as keyword * also add generator keywords --- dart-lang/src/main/resources/dart.keywords | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dart-lang/src/main/resources/dart.keywords b/dart-lang/src/main/resources/dart.keywords index 746a34e..d4cadf9 100644 --- a/dart-lang/src/main/resources/dart.keywords +++ b/dart-lang/src/main/resources/dart.keywords @@ -2,6 +2,7 @@ abstract as assert async +async* await break case @@ -35,6 +36,7 @@ null on operator part +required rethrow return set @@ -42,6 +44,7 @@ static super switch sync +sync* this throw true @@ -51,3 +54,4 @@ void while with yield +yield* From f3d5cd0f9d0427958a9d374c82c09d53dea66a09 Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Mon, 26 Apr 2021 21:38:37 +0200 Subject: [PATCH 17/25] doc : CHANGELOG update --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4afd30..fddafff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,8 @@ #### Enhancements -- Allow re-using an existing dartanalyzer report with `sonar.dart.analysis.reportPath` -- Add missing dart keywords `extension`, `on`, `mixin` +- Allow re-using an existing dartanalyzer report with `sonar.dart.analysis.reportPath` (thanks to [Peter Leibiger](https://github.com/kuhnroyal)) +- Add missing dart keywords `extension`, `on`, `mixin` (thanks to [Peter Leibiger](https://github.com/kuhnroyal)) #### Bug Fixes From 9868de389656ca567fc827427f9ed31b7cb32ee8 Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Mon, 26 Apr 2021 22:12:22 +0200 Subject: [PATCH 18/25] fix (analyzer): wrong import --- .../dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java index bcf1e50..961478c 100644 --- a/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java +++ b/dart-lang/src/main/java/fr/insideapp/sonarqube/dart/lang/issues/dartanalyzer/DartAnalyzerSensor.java @@ -19,7 +19,6 @@ */ package fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer; -import com.google.common.io.Files; import com.google.common.io.Resources; import fr.insideapp.sonarqube.dart.lang.Dart; import fr.insideapp.sonarqube.dart.lang.DartSensor; @@ -41,6 +40,7 @@ import java.io.File; import java.io.IOException; import java.net.URL; +import java.nio.file.Files; import java.util.ArrayList; import java.util.HashSet; import java.util.List; From 26709d13bbc524b845339f4c85ef4031630698a4 Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Mon, 26 Apr 2021 22:14:23 +0200 Subject: [PATCH 19/25] doc: CHANGELOG update --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fddafff..ec48ba9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ #### Bug Fixes -- None. +- Ensure analyzer encoding is UTF-8 (thanks to [Daniel Morawetz](https://github.com/dmorawetz)) ## 0.3.1 From d30cb439859f429ad093d3a8ac586a10e7cd1689 Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Mon, 26 Apr 2021 22:21:59 +0200 Subject: [PATCH 20/25] doc: CHANGELOG update --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec48ba9..58e8237 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Allow re-using an existing dartanalyzer report with `sonar.dart.analysis.reportPath` (thanks to [Peter Leibiger](https://github.com/kuhnroyal)) - Add missing dart keywords `extension`, `on`, `mixin` (thanks to [Peter Leibiger](https://github.com/kuhnroyal)) +- Add pedantic 1.9.0 profile (thanks to [Daniel Morawetz](https://github.com/dmorawetz)) #### Bug Fixes From 773e13696d001815bc60234084e20a299adb7f99 Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Mon, 26 Apr 2021 23:34:41 +0200 Subject: [PATCH 21/25] fix (plugin): added missing imports --- .../main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java index 396524e..e9bf9e5 100644 --- a/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java +++ b/sonar-flutter-plugin/src/main/java/fr/insideapp/sonarqube/flutter/FlutterPlugin.java @@ -22,6 +22,8 @@ import fr.insideapp.sonarqube.dart.lang.Dart; import fr.insideapp.sonarqube.dart.lang.DartSensor; import fr.insideapp.sonarqube.dart.lang.issues.DartProfile; +import fr.insideapp.sonarqube.dart.lang.issues.DartProfilePedantic190; +import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.AnalyzerMode; import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.DartAnalyzerRulesDefinition; import fr.insideapp.sonarqube.dart.lang.issues.dartanalyzer.DartAnalyzerSensor; import fr.insideapp.sonarqube.flutter.coverage.FlutterCoverageSensor; From 91cad5351d25ba7985bc733f0fa3ccf0ccc2e1d0 Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Mon, 26 Apr 2021 23:50:16 +0200 Subject: [PATCH 22/25] doc: README and CHANGELOG update --- CHANGELOG.md | 1 + README.md | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e8237..445b987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - Allow re-using an existing dartanalyzer report with `sonar.dart.analysis.reportPath` (thanks to [Peter Leibiger](https://github.com/kuhnroyal)) - Add missing dart keywords `extension`, `on`, `mixin` (thanks to [Peter Leibiger](https://github.com/kuhnroyal)) - Add pedantic 1.9.0 profile (thanks to [Daniel Morawetz](https://github.com/dmorawetz)) +- Faster analysis with 'flutter analyze' and support for different analysis modes with `sonar.flutter.analyzer.mode` (thanks to [Marc Reichelt](https://github.com/mreichelt)) #### Bug Fixes diff --git a/README.md b/README.md index 476c642..9bc6b68 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,19 @@ sonar.projectVersion=1.0 # Use commas to specify more than one folder. sonar.sources=lib sonar.tests=test - + # Encoding of the source code. Default is default system encoding. sonar.sourceEncoding=UTF-8 + +# Allows reuse of an existing analyzer report +# sonar.dart.analysis.reportPath= + +# Analyzer mode +# Can be: +# - flutter (flutter analyze) - default +# - dart (dart analyze) +# - legacy (dartanalyzer) +# sonar.flutter.analyzer.mode= ``` *For a complete list of available options, please refer to the [SonarQube documentation](https://docs.sonarqube.org/latest/analysis/analysis-parameters/).* From 29d103fc6cf784ce95c65a6be5a5cbfff05e363c Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Tue, 27 Apr 2021 00:21:46 +0200 Subject: [PATCH 23/25] [maven-release-plugin] prepare release 0.3.2 --- dart-lang/pom.xml | 2 +- pom.xml | 4 ++-- sonar-flutter-plugin/pom.xml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dart-lang/pom.xml b/dart-lang/pom.xml index 5122dbb..9307f67 100644 --- a/dart-lang/pom.xml +++ b/dart-lang/pom.xml @@ -3,7 +3,7 @@ sonar-flutter fr.insideapp.sonarqube - 0.3-SNAPSHOT + 0.3.2 4.0.0 diff --git a/pom.xml b/pom.xml index a7d7d57..b965984 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ fr.insideapp.sonarqube sonar-flutter - 0.3-SNAPSHOT + 0.3.2 pom @@ -48,7 +48,7 @@ scm:git:git@github.com:insideapp-oss/sonar-flutter.git scm:git:git@github.com:insideapp-oss/sonar-flutter.git https://github.com/insideapp-oss/sonar-flutter - HEAD + 0.3.2 diff --git a/sonar-flutter-plugin/pom.xml b/sonar-flutter-plugin/pom.xml index 3c4312a..36a912a 100644 --- a/sonar-flutter-plugin/pom.xml +++ b/sonar-flutter-plugin/pom.xml @@ -4,7 +4,7 @@ sonar-flutter fr.insideapp.sonarqube - 0.3-SNAPSHOT + 0.3.2 4.0.0 @@ -17,7 +17,7 @@ fr.insideapp.sonarqube dart-lang - 0.3-SNAPSHOT + 0.3.2 From 1af191bbdefa37605e0197c7d4a339ec9efe8dcc Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Tue, 27 Apr 2021 00:21:53 +0200 Subject: [PATCH 24/25] [maven-release-plugin] prepare for next development iteration --- dart-lang/pom.xml | 2 +- pom.xml | 4 ++-- sonar-flutter-plugin/pom.xml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dart-lang/pom.xml b/dart-lang/pom.xml index 9307f67..5122dbb 100644 --- a/dart-lang/pom.xml +++ b/dart-lang/pom.xml @@ -3,7 +3,7 @@ sonar-flutter fr.insideapp.sonarqube - 0.3.2 + 0.3-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index b965984..a7d7d57 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ fr.insideapp.sonarqube sonar-flutter - 0.3.2 + 0.3-SNAPSHOT pom @@ -48,7 +48,7 @@ scm:git:git@github.com:insideapp-oss/sonar-flutter.git scm:git:git@github.com:insideapp-oss/sonar-flutter.git https://github.com/insideapp-oss/sonar-flutter - 0.3.2 + HEAD diff --git a/sonar-flutter-plugin/pom.xml b/sonar-flutter-plugin/pom.xml index 36a912a..3c4312a 100644 --- a/sonar-flutter-plugin/pom.xml +++ b/sonar-flutter-plugin/pom.xml @@ -4,7 +4,7 @@ sonar-flutter fr.insideapp.sonarqube - 0.3.2 + 0.3-SNAPSHOT 4.0.0 @@ -17,7 +17,7 @@ fr.insideapp.sonarqube dart-lang - 0.3.2 + 0.3-SNAPSHOT From b45b8045b878b1ef39276325aaa44abb43e908da Mon Sep 17 00:00:00 2001 From: Gilles Grousset Date: Tue, 27 Apr 2021 00:35:57 +0200 Subject: [PATCH 25/25] updated version to 0.3.2 --- CHANGELOG.md | 2 +- dart-lang/pom.xml | 2 +- pom.xml | 2 +- sonar-flutter-plugin/pom.xml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 445b987..8c8ffdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # SonarQube Plugin for Flutter / Dart -## develop +## 0.3.2 #### Breaking diff --git a/dart-lang/pom.xml b/dart-lang/pom.xml index 5122dbb..9307f67 100644 --- a/dart-lang/pom.xml +++ b/dart-lang/pom.xml @@ -3,7 +3,7 @@ sonar-flutter fr.insideapp.sonarqube - 0.3-SNAPSHOT + 0.3.2 4.0.0 diff --git a/pom.xml b/pom.xml index a7d7d57..1899b0a 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ fr.insideapp.sonarqube sonar-flutter - 0.3-SNAPSHOT + 0.3.2 pom diff --git a/sonar-flutter-plugin/pom.xml b/sonar-flutter-plugin/pom.xml index 3c4312a..36a912a 100644 --- a/sonar-flutter-plugin/pom.xml +++ b/sonar-flutter-plugin/pom.xml @@ -4,7 +4,7 @@ sonar-flutter fr.insideapp.sonarqube - 0.3-SNAPSHOT + 0.3.2 4.0.0 @@ -17,7 +17,7 @@ fr.insideapp.sonarqube dart-lang - 0.3-SNAPSHOT + 0.3.2