diff --git a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoveragePlugin.kt b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoveragePlugin.kt index 39c7ed35..c2078f5c 100644 --- a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoveragePlugin.kt +++ b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoveragePlugin.kt @@ -13,7 +13,7 @@ class ProcessTestCoveragePlugin : Plugin { context.addExtensions(ProcessTestCoverageSensor::class.java, ProcessTestCoverageProjectSensor::class.java) context.addExtension(ProcessTestCoveragePage::class.java) context.addExtension( - PropertyDefinition.builder(ReportPathsProvider.REPORT_PATHS_PROPERTY_KEY) + PropertyDefinition.builder(ReportsProvider.REPORT_PATHS_PROPERTY_KEY) .onQualifiers(Qualifiers.PROJECT) .multiValues(true) .category("Process Test Coverage") diff --git a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoverageProjectSensor.kt b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoverageProjectSensor.kt index 8e0ecc7d..8ea41a21 100644 --- a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoverageProjectSensor.kt +++ b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoverageProjectSensor.kt @@ -20,13 +20,13 @@ class ProcessTestCoverageProjectSensor : ProjectSensor { } override fun execute(context: SensorContext) { - val reportPathsProvider = ReportPathsProvider(context) + val reportsProvider = ReportsProvider(context) val importer = ReportImporter(context) - importReports(reportPathsProvider, importer) + importReports(reportsProvider, importer) } - private fun importReports(reportPathsProvider: ReportPathsProvider, importer: ReportImporter) { - val reportPaths = reportPathsProvider.getPaths() + private fun importReports(reportsProvider: ReportsProvider, importer: ReportImporter) { + val reportPaths = reportsProvider.getProjectReports() if (reportPaths.isEmpty()) { LOG.info("No report imported, no coverage information will be imported by Process Test Coverage Report Importer") return diff --git a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoverageSensor.kt b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoverageSensor.kt index 3660a749..a9924d04 100644 --- a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoverageSensor.kt +++ b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ProcessTestCoverageSensor.kt @@ -20,13 +20,13 @@ class ProcessTestCoverageSensor : Sensor { } override fun execute(context: SensorContext) { - val reportPathsProvider = ReportPathsProvider(context) + val reportsProvider = ReportsProvider(context) val importer = ReportImporter(context) - importReports(reportPathsProvider, importer) + importReports(reportsProvider, importer) } - private fun importReports(reportPathsProvider: ReportPathsProvider, importer: ReportImporter) { - val reportPaths = reportPathsProvider.getPaths() + private fun importReports(reportsProvider: ReportsProvider, importer: ReportImporter) { + val reportPaths = reportsProvider.getModuleReports() if (reportPaths.isEmpty()) { LOG.info("No report imported, no coverage information will be imported by Process Test Coverage Report Importer") return diff --git a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ReportPathsProvider.kt b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ReportPathsProvider.kt deleted file mode 100644 index 418d0d27..00000000 --- a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ReportPathsProvider.kt +++ /dev/null @@ -1,38 +0,0 @@ -package org.camunda.community.process_test_coverage.sonar - -import org.sonar.api.batch.sensor.SensorContext -import org.sonar.api.utils.log.Logger -import org.sonar.api.utils.log.Loggers -import java.nio.file.Path - - -class ReportPathsProvider( - private val context: SensorContext -) { - - companion object { - private val LOG: Logger = Loggers.get(ReportPathsProvider::class.java) - private val DEFAULT_PATHS = arrayOf("**/process-test-coverage/**/report.json") - const val REPORT_PATHS_PROPERTY_KEY = "sonar.process-test-coverage.jsonReportPaths" - } - - fun getPaths(): Collection { - val baseDir: Path = context.fileSystem().baseDir().toPath().toAbsolutePath() - val patternPathList = context.config().getStringArray(REPORT_PATHS_PROPERTY_KEY) - .filter { it.isNotEmpty() } - .plus(DEFAULT_PATHS) - val reportPaths: MutableSet = HashSet() - if (patternPathList.isNotEmpty()) { - for (patternPath in patternPathList) { - LOG.info("Scanning {} with pattern {}", baseDir, patternPath) - val paths: List = WildcardPatternFileScanner.scan(baseDir, patternPath) - if (paths.isEmpty() && patternPathList.size > 1) { - LOG.info("Coverage report doesn't exist for pattern: '{}'", patternPath) - } - reportPaths.addAll(paths) - } - } - return reportPaths - } - -} \ No newline at end of file diff --git a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ReportsProvider.kt b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ReportsProvider.kt new file mode 100644 index 00000000..e04015c6 --- /dev/null +++ b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/ReportsProvider.kt @@ -0,0 +1,49 @@ +package org.camunda.community.process_test_coverage.sonar + +import org.sonar.api.batch.sensor.SensorContext +import org.sonar.api.utils.log.Logger +import org.sonar.api.utils.log.Loggers +import java.nio.file.FileSystems +import java.nio.file.Files +import java.nio.file.Path +import kotlin.streams.toList as streamToList + + +class ReportsProvider( + private val context: SensorContext +) { + + companion object { + private val LOG: Logger = Loggers.get(ReportsProvider::class.java) + private val DEFAULT_PATHS = arrayOf("target/process-test-coverage/**/report.json") + const val REPORT_PATHS_PROPERTY_KEY = "sonar.process-test-coverage.jsonReportPaths" + } + + fun getProjectReports(): Collection { + val pathPattern = getPathPattern("**/") + val matcher = FileSystems.getDefault().getPathMatcher("glob:$pathPattern") + return Files.find(context.fileSystem().baseDir().toPath(), Int.MAX_VALUE, { path, _ -> + matcher.matches(path) + }).streamToList() + } + + fun getModuleReports(): Collection { + val pathPattern = getPathPattern("") + val matcher = FileSystems.getDefault().getPathMatcher("glob:$pathPattern") + return Files.find(context.fileSystem().baseDir().toPath(), Int.MAX_VALUE, { path, _ -> + val relativePath = context.fileSystem().baseDir().toPath().relativize(path) + matcher.matches(relativePath) + }).streamToList() + } + + private fun getPathPattern(prefix: String): String { + val paths = context.config().getStringArray(REPORT_PATHS_PROPERTY_KEY) + .filter { it.isNotEmpty() } + .plus(DEFAULT_PATHS) + LOG.info("Configured paths are $paths") + val pattern = paths.joinToString(prefix = "{", postfix = "}", separator = ",") { "$prefix$it" } + LOG.info("Using pattern $pattern for reports") + return pattern + } + +} \ No newline at end of file diff --git a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/WildcardPatternFileScanner.kt b/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/WildcardPatternFileScanner.kt deleted file mode 100644 index 509c5ac1..00000000 --- a/extension/sonar-process-test-coverage-plugin/src/main/kotlin/org/camunda/community/process_test_coverage/sonar/WildcardPatternFileScanner.kt +++ /dev/null @@ -1,98 +0,0 @@ -package org.camunda.community.process_test_coverage.sonar - -import org.sonar.api.utils.WildcardPattern -import org.sonar.api.utils.log.Logger -import org.sonar.api.utils.log.Loggers -import java.io.File -import java.io.IOException -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths - - -object WildcardPatternFileScanner { - - private val LOG: Logger = Loggers.get(WildcardPatternFileScanner::class.java) - private const val SEARCH_MAX_DEPTH = 64 - private const val PATH_MATCHER_SPECIAL_CHAR = "*?" - - fun scan(baseDirectory: Path, patternPath: String): List { - val unixLikePatternPath = toUnixLikePath(patternPath) - val specialCharIndex = indexOfMatcherSpecialChar(unixLikePatternPath) - if (specialCharIndex == -1) { - return scanNonWildcardPattern(baseDirectory, unixLikePatternPath) - } else { - // For performance reason, we don't want to scan recursively all files in baseDirectory - // when patternPath start with "none wildcard" subfolder names. For example, - // scanWildcardPattern("/base", "sub1/sub2/**/file*.xml") is converted into - // scanWildcardPattern("/base/sub1/sub2", "**/file*.xml") - val additionalBaseDirectoryPart = unixLikePatternPath.lastIndexOf('/', specialCharIndex) - if (additionalBaseDirectoryPart != -1) { - val additionalBaseDirectory: Path = - toFileSystemPath(unixLikePatternPath.substring(0, additionalBaseDirectoryPart + 1)) - val remainingWildcardPart = unixLikePatternPath.substring(additionalBaseDirectoryPart + 1) - val moreSpecificBaseDirectory: Path = baseDirectory.resolve(additionalBaseDirectory) - return scanWildcardPattern(moreSpecificBaseDirectory, remainingWildcardPart) - } else { - return scanWildcardPattern(baseDirectory, unixLikePatternPath) - } - } - } - - private fun scanNonWildcardPattern(baseDirectory: Path, unixLikePath: String): List { - val path: Path = baseDirectory.resolve(toFileSystemPath(unixLikePath)) - return if (Files.isRegularFile(path)) { - listOf(path) - } else emptyList() - } - - private fun scanWildcardPattern(baseDirectory: Path, unixLikePatternPath: String): List { - if (!Files.exists(baseDirectory)) { - return emptyList() - } - try { - val absoluteBaseDirectory: Path = baseDirectory.toRealPath() - if (absoluteBaseDirectory == absoluteBaseDirectory.root) { - throw IOException("For performance reason, wildcard pattern search is not possible from filesystem root") - } - val paths: MutableList = mutableListOf() - val matcher = WildcardPattern.create(toUnixLikePath(absoluteBaseDirectory.toString()) + "/" + unixLikePatternPath) - Files.walk(absoluteBaseDirectory, SEARCH_MAX_DEPTH).use { stream -> - stream - .filter(Files::isRegularFile) - .filter { path -> matcher.match(toUnixLikePath(path.toString())) } - .forEach(paths::add) - } - return paths - } catch (e: IOException) { - LOG.error( - "Failed to get Process Test Coverage report paths: Scanning '" + baseDirectory + "' with pattern '" + unixLikePatternPath + "'" + - " threw a " + e.javaClass.simpleName + ": " + e.message - ) - return emptyList() - } catch (e: RuntimeException) { - LOG.error( - ("Failed to get Process Test Coverage report paths: Scanning '" + baseDirectory + "' with pattern '" + unixLikePatternPath + "'" + - " threw a " + e.javaClass.simpleName + ": " + e.message) - ) - return emptyList() - } - } - - private fun toUnixLikePath(path: String): String { - return if (path.indexOf('\\') != -1) path.replace('\\', '/') else path - } - - private fun toFileSystemPath(unixLikePath: String): Path { - return Paths.get(unixLikePath.replace('/', File.separatorChar)) - } - - private fun indexOfMatcherSpecialChar(path: String): Int { - for (i in path.indices) { - if (PATH_MATCHER_SPECIAL_CHAR.indexOf(path[i]) != -1) { - return i - } - } - return -1 - } -} \ No newline at end of file