diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f12d69..d5084f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Detekt - Changelog +#### 2.0.0 + +- Rename to sonar-detekt +- Based on detekt 1.7.4 +- All redundant features to official SonarKotlin plugin got dropped +- Compatible with SonarKotlin, allows mixing rulesets + #### 1.5.0 - Updated to detekt 1.7.4 diff --git a/README.md b/README.md index 6c7be37..c5cb606 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# sonar-kotlin +# sonar-detekt [![Join the chat at https://kotlinlang.slack.com/messages/C88E12QH4/convo/C0BQ5GZ0S-1511956674.000289/](https://img.shields.io/badge/chat-on_slack-red.svg?style=flat-square)](https://kotlinlang.slack.com/messages/C88E12QH4/convo/C0BQ5GZ0S-1511956674.000289/) ![Pre Merge Checks](https://github.com/detekt/sonar-kotlin/workflows/Pre%20Merge%20Checks/badge.svg) @@ -8,25 +8,34 @@ ### Features -- Integrates [detekt](https://github.com/arturbosch/detekt) for code analysis -- Default quality profile `detekt active` (80 rules) and `detekt all` (164 rules) -- Syntax highlighting -- Supports SonarQube 6.7.7 and up -- Supports detekt's `yaml config` and `baseline.xml` (also `path filters`) -- Jacoco support -- Lines of code and complexity metrics +- Integrates [detekt](https://github.com/arturbosch/detekt) for static code analysis +- Default quality profiles `detekt active` (80+ rules) and `detekt all` (164+ rules) +- Supports SonarQube 7.9.3+ +- Supports detekt's `yaml config`, `baseline.xml` and `excludes` +- Seamless integration with official SonarKotlin (no redundant features) + +#### Non supported features as of 2.x.x + +- code coverage +- test reports +- syntax highlighting +- metrics + +The official SonarKotlin plugin now supports these features. ### Usage -This sonar-kotlin is not the official sonarqube plugin. -It was released before the official plugin and uses the same plugin key 'kotlin'. -That means you can't use this plugin together with the official one. +#### Sonar Update Center + +- TODO + +#### Building from source -- `git clone https://github.com/arturbosch/sonar-kotlin` -- `cd sonar-kotlin` -- `mvn package` -- `cp target/sonar-kotlin-[enter_version].jar $SONAR_HOME/extensions/plugins` -- `cd $SONAR_HOME/bin/[your_os]` +- `git clone https://github.com/detekt/sonar-detekt` +- `cd sonar-detekt` +- `mvn verify` +- `cp target/sonar-detekt-.jar $SONAR_HOME/extensions/plugins` +- `cd $SONAR_HOME/bin/` - `./sonar.sh restart` ### Configurations and Baselines (and Filters) @@ -48,14 +57,14 @@ To make use of this features, you have to set up some properties: ![configs](img/config.png) -__Detekt path filters__ support multiple regex entries by adding a `,` for separating. -__Detekt yaml configuration path__ also supports multiple configuration files where the first entered override some +__detekt path filters__ support multiple regex entries by adding a `,` for separating. +__detekt yaml configuration path__ also supports multiple configuration files where the first entered override some values of the later added config files. ##### Limitations Sonar analyzes each module individually which makes it harder to search for your config files. -If you use relative paths, sonar-kotlin first tries to find the provided path inside this module and if it can't find +If you use relative paths, sonar-detekt first tries to find the provided path inside this module and if it can't find it, we are searching for the file in the parent folder. This leads to the limitation that only projects with sub-projects of depth 1 are supported. If you need more config files in your project hierarchies, provide them in the sub-projects with the same relative path available. diff --git a/pom.xml b/pom.xml index 959e118..ce18229 100644 --- a/pom.xml +++ b/pom.xml @@ -3,9 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.gitlab.arturbosch - sonar-kotlin - 1.5.0 + io.github.detekt + sonar-detekt + 2.0.0-RC1 sonar-plugin @@ -13,7 +13,7 @@ 1.3.71 2.0.10 1.7.4 - 6.7.7 + 7.9.3 3.15.0 1.78 1.9.3 @@ -74,11 +74,6 @@ detekt-formatting ${detekt.version} - - org.sonarsource.java - java-jacoco - 5.7.0.15470 - org.jetbrains.kotlin kotlin-compiler-embeddable @@ -140,8 +135,8 @@ io.gitlab.arturbosch.detekt.sonar.DetektPlugin Sonarqube plugin for Kotlin based on detekt. - kotlin - Kotlin + detekt + detekt https://github.com/detekt/sonar-kotlin https://github.com/detekt/sonar-kotlin @@ -237,6 +232,7 @@ ${project.basedir}/reports/baseline.xml + **/resources/** diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/DetektPlugin.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/DetektPlugin.kt index cdc1551..c802a86 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/DetektPlugin.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/DetektPlugin.kt @@ -1,33 +1,18 @@ package io.gitlab.arturbosch.detekt.sonar -import io.gitlab.arturbosch.detekt.sonar.foundation.KotlinClasspath -import io.gitlab.arturbosch.detekt.sonar.foundation.KotlinLanguage +import io.gitlab.arturbosch.detekt.sonar.foundation.DetektProfile import io.gitlab.arturbosch.detekt.sonar.foundation.propertyDefinitions -import io.gitlab.arturbosch.detekt.sonar.jacoco.KotlinJaCoCoSensor -import io.gitlab.arturbosch.detekt.sonar.profiles.KotlinProfile import io.gitlab.arturbosch.detekt.sonar.rules.DetektRulesDefinition -import io.gitlab.arturbosch.detekt.sonar.sensor.DetektMetrics import io.gitlab.arturbosch.detekt.sonar.sensor.DetektSensor -import io.gitlab.arturbosch.detekt.sonar.surefire.KotlinSurefireParser -import io.gitlab.arturbosch.detekt.sonar.surefire.KotlinSurefireSensor import org.sonar.api.Plugin -import org.sonar.java.JavaTestClasspath class DetektPlugin : Plugin { override fun define(context: Plugin.Context) { context.addExtensions(listOf( - KotlinLanguage::class.java, - KotlinProfile::class.java, + DetektProfile::class.java, DetektSensor::class.java, - DetektRulesDefinition::class.java, - DetektMetrics::class.java, - KotlinClasspath::class.java, - JavaTestClasspath::class.java, - KotlinJaCoCoSensor::class.java, - // Tests - KotlinSurefireSensor::class.java, - KotlinSurefireParser::class.java + DetektRulesDefinition::class.java )) context.addExtensions(propertyDefinitions) } diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/profiles/KotlinProfile.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/DetektProfile.kt similarity index 79% rename from src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/profiles/KotlinProfile.kt rename to src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/DetektProfile.kt index 6624df9..e908a63 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/profiles/KotlinProfile.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/DetektProfile.kt @@ -1,8 +1,5 @@ -package io.gitlab.arturbosch.detekt.sonar.profiles +package io.gitlab.arturbosch.detekt.sonar.foundation -import io.gitlab.arturbosch.detekt.sonar.foundation.DETEKT_FAIL_FAST -import io.gitlab.arturbosch.detekt.sonar.foundation.DETEKT_WAY -import io.gitlab.arturbosch.detekt.sonar.foundation.KEY import io.gitlab.arturbosch.detekt.sonar.rules.DetektRuleKey import io.gitlab.arturbosch.detekt.sonar.rules.ruleKeys import io.gitlab.arturbosch.detekt.sonar.rules.severityTranslations @@ -10,7 +7,7 @@ import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition typealias RuleContext = BuiltInQualityProfilesDefinition.Context -class KotlinProfile : BuiltInQualityProfilesDefinition { +class DetektProfile : BuiltInQualityProfilesDefinition { override fun define(context: RuleContext) { registerProfile(context, DETEKT_WAY, ruleKeys.filter { it.active }, isDefault = true) @@ -23,7 +20,7 @@ class KotlinProfile : BuiltInQualityProfilesDefinition { rules: List, isDefault: Boolean ) { - val profile = context.createBuiltInQualityProfile(name, KEY) + val profile = context.createBuiltInQualityProfile(name, LANGUAGE_KEY) profile.isDefault = isDefault for (ruleKey in rules) { diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/Kotlin.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/Kotlin.kt index 5595576..e685cd6 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/Kotlin.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/Kotlin.kt @@ -3,19 +3,13 @@ package io.gitlab.arturbosch.detekt.sonar.foundation import io.gitlab.arturbosch.detekt.sonar.DetektPlugin import org.sonar.api.utils.log.Logger import org.sonar.api.utils.log.Loggers -import java.util.Optional -const val KEY = "kotlin" -const val NAME = "Kotlin" -const val FILE_SUFFIX = ".kt" -const val SCRIPT_SUFFIX = ".kts" +const val LANGUAGE_KEY = "kotlin" +const val REPOSITORY_KEY = "sonar-detekt" const val DETEKT_WAY = "detekt active" const val DETEKT_FAIL_FAST = "detekt all" const val DETEKT_SENSOR = "DetektSensor" -const val DETEKT_REPOSITORY = "detekt-kotlin" const val DETEKT_ANALYZER = "Detekt-based Kotlin Analyzer" val logger: Logger = Loggers.get(DetektPlugin::class.java) - -fun Optional.unwrap(): T? = orElse(null) diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinClasspath.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinClasspath.kt deleted file mode 100644 index f9fa4e7..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinClasspath.kt +++ /dev/null @@ -1,69 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.foundation - -import org.sonar.api.batch.fs.FilePredicates -import org.sonar.api.batch.fs.FileSystem -import org.sonar.api.batch.fs.InputFile -import org.sonar.api.config.Configuration -import org.sonar.api.utils.log.Loggers -import org.sonar.api.utils.log.Profiler -import org.sonar.java.AbstractJavaClasspath -import org.sonar.java.AnalysisException -import org.sonar.java.JavaClasspath - -private val type = InputFile.Type.MAIN - -/** - * This class is based on [JavaClasspath] adding kotlin compiled .class files - * to binaries using the default kotlin .class files location. - */ -class KotlinClasspath(settings: Configuration, fs: FileSystem) : AbstractJavaClasspath(settings, fs, type) { - private val log = Loggers.get(JavaClasspath::class.java) - - override fun init() { - if (!initialized) { - validateLibraries = fs.hasFiles(this.fs.predicates().all()) - val profiler = Profiler.create(log).startInfo("KotlinClasspath initialization") - initialized = true - - val libraries = this.getFilesFromProperty("sonar.java.libraries") - val binaryFiles = ArrayList(this.getFilesFromProperty("sonar.java.binaries")) - - // assume a path with `kotlin-classes` within libraries is a kotlin .class files location - libraries.filter { it.path.contains("kotlin-classes") }.forEach { - libraries.remove(it) - binaryFiles.add(it) - } - - if (binaryFiles.isEmpty() && hasMoreThanOneKotlinFile()) { - throw AnalysisException( - "Please provide compiled classes of your project with sonar.java.binaries property" - ) - } - - binaries = binaryFiles - if (libraries.isEmpty() && hasKotlinSources()) { - log.warn( - "Bytecode of dependencies was not provided for analysis of source files," + - " you might end up with less precise results." + - " Bytecode can be provided using sonar.java.libraries property" - ) - } - - elements = ArrayList(binaries) - elements.addAll(libraries) - profiler.stopInfo() - } - } - - private fun hasKotlinSources(): Boolean { - return fs.hasFiles(ktPredicate(fs.predicates())) - } - - private fun hasMoreThanOneKotlinFile(): Boolean { - return fs.inputFiles(ktPredicate(fs.predicates())) - .filterIndexed { i, _ -> i > 1 } - .any() - } - - private fun ktPredicate(p: FilePredicates) = p.and(p.hasLanguage(KEY), p.hasType(type)) -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinLanguage.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinLanguage.kt deleted file mode 100644 index 44d24a7..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinLanguage.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.foundation - -import org.sonar.api.resources.AbstractLanguage - -class KotlinLanguage : AbstractLanguage(KEY, NAME) { - - override fun getFileSuffixes(): Array = arrayOf(FILE_SUFFIX, SCRIPT_SUFFIX) -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinSyntax.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinSyntax.kt deleted file mode 100644 index 7c695bb..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/KotlinSyntax.kt +++ /dev/null @@ -1,83 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.foundation - -import org.jetbrains.kotlin.com.intellij.lang.ASTNode -import org.jetbrains.kotlin.com.intellij.openapi.editor.Document -import org.jetbrains.kotlin.com.intellij.psi.PsiElement -import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.KtAnnotationEntry -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType -import org.sonar.api.batch.fs.InputFile -import org.sonar.api.batch.sensor.SensorContext -import org.sonar.api.batch.sensor.highlighting.TypeOfText - -object KotlinSyntax { - - @Suppress("ComplexMethod", "TooGenericExceptionCaught") - fun processFile(inputFile: InputFile, ktFile: KtFile, context: SensorContext) { - val syntax = context.newHighlighting().onFile(inputFile) - val document: Document = ktFile.viewProvider.document ?: return - - fun positions(psi: PsiElement) = - PsiDiagnosticUtils.offsetToLineAndColumn(document, psi.textRange.startOffset) to - PsiDiagnosticUtils.offsetToLineAndColumn(document, psi.textRange.endOffset) - - fun highlightByType(psi: PsiElement, type: TypeOfText) { - try { - val (start, end) = positions(psi) - syntax.highlight( - inputFile.newRange( - start.line, - start.column - 1, - end.line, - end.column - 1 - ), - type - ) - } catch (error: Throwable) { - logger.warn( - "Could not highlight psi element '$psi'" + - " with content '${psi.text}'" + - " for file '${inputFile.uri()}'." - ) - logger.warn(error.localizedMessage) - } - } - - fun highlightByType(astNode: ASTNode, type: TypeOfText) { - val psi = astNode.psi - if (psi != null) { - highlightByType(psi, type) - } - } - - fun handleAnnotation(astNode: ASTNode) { - val annotationEntry = astNode.psi - ?.getNonStrictParentOfType(KtAnnotationEntry::class.java) - if (annotationEntry != null) { - highlightByType(annotationEntry, TypeOfText.ANNOTATION) - } - } - - ktFile.node.visitTokens { - when (it.elementType) { - in KtTokens.KEYWORDS -> highlightByType(it, TypeOfText.KEYWORD) - in KtTokens.SOFT_KEYWORDS -> highlightByType(it, TypeOfText.KEYWORD) - in KtTokens.STRINGS -> highlightByType(it, TypeOfText.STRING) - in KtTokens.COMMENTS -> highlightByType(it, TypeOfText.COMMENT) - KtTokens.OPEN_QUOTE, KtTokens.CLOSING_QUOTE -> highlightByType(it, TypeOfText.STRING) - KtTokens.AT -> handleAnnotation(it) - KtTokens.SHORT_TEMPLATE_ENTRY_START, KtTokens.LONG_TEMPLATE_ENTRY_START, KtTokens.ESCAPE_SEQUENCE, - KtTokens.LONG_TEMPLATE_ENTRY_END -> highlightByType(it, TypeOfText.ANNOTATION) - } - } - - syntax.save() - } - - private fun ASTNode.visitTokens(currentNode: (node: ASTNode) -> Unit) { - currentNode(this) - getChildren(null).forEach { it.visitTokens(currentNode) } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/NoAutoCorrectConfig.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/NoAutoCorrectConfig.kt deleted file mode 100644 index 9a9bcdf..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/NoAutoCorrectConfig.kt +++ /dev/null @@ -1,21 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.foundation - -import io.gitlab.arturbosch.detekt.api.Config - -/** - * Config wrapper for disabling automatic correction - */ -@Suppress("UNCHECKED_CAST") -class NoAutoCorrectConfig(private val config: Config) : Config { - - override fun subConfig(key: String): Config = NoAutoCorrectConfig(config.subConfig(key)) - - override fun valueOrDefault(key: String, default: T): T { - if ("autoCorrect" == key) { - return false as T - } - return config.valueOrDefault(key, default) - } - - override fun valueOrNull(key: String): T? = config.valueOrNull(key) -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJaCoCoSensor.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJaCoCoSensor.kt deleted file mode 100644 index 4016d3c..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJaCoCoSensor.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2010-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.jacoco - -import io.gitlab.arturbosch.detekt.sonar.foundation.KEY -import io.gitlab.arturbosch.detekt.sonar.foundation.KotlinClasspath -import io.gitlab.arturbosch.detekt.sonar.foundation.unwrap -import org.sonar.api.batch.fs.FileSystem -import org.sonar.api.batch.sensor.Sensor -import org.sonar.api.batch.sensor.SensorContext -import org.sonar.api.batch.sensor.SensorDescriptor -import org.sonar.api.config.Configuration -import org.sonar.plugins.jacoco.JaCoCoExtensions.IT_REPORT_PATH_PROPERTY -import org.sonar.plugins.jacoco.JaCoCoExtensions.LOG -import org.sonar.plugins.jacoco.JaCoCoExtensions.REPORT_MISSING_FORCE_ZERO -import org.sonar.plugins.jacoco.JaCoCoExtensions.REPORT_PATHS_PROPERTY -import org.sonar.plugins.jacoco.JaCoCoExtensions.REPORT_PATH_PROPERTY -import org.sonar.plugins.jacoco.JaCoCoReportMerger -import org.sonar.plugins.java.api.JavaResourceLocator -import java.io.File -import java.util.HashSet - -@Suppress("ALL") -open class KotlinJaCoCoSensor( - fileSystem: FileSystem, - javaResourceLocator: JavaResourceLocator, - private val kotlinClasspath: KotlinClasspath -) : Sensor { - private val javaResourceLocator = KotlinJavaResourceLocator(javaResourceLocator, fileSystem) - - override fun describe(descriptor: SensorDescriptor) { - descriptor.onlyOnLanguage(KEY).name("KotlinJaCoCoSensor") - } - - override fun execute(context: SensorContext) { - if (context.config().hasKey(REPORT_MISSING_FORCE_ZERO)) { - LOG.warn("Property '{}' is deprecated and its value will be ignored.", REPORT_MISSING_FORCE_ZERO) - } - val reportPaths = getReportPaths(context) - if (reportPaths.isEmpty()) { - return - } - // Merge JaCoCo reports - val reportMerged: File - if (reportPaths.size == 1) { - reportMerged = reportPaths.iterator().next() - } else { - reportMerged = File(context.fileSystem().workDir(), JACOCO_MERGED_FILENAME) - reportMerged.parentFile.mkdirs() - JaCoCoReportMerger.mergeReports(reportMerged, *reportPaths.toTypedArray()) - } - KotlinJacocoReportAnalyzer(javaResourceLocator, kotlinClasspath, report = reportMerged).analyse(context) - } - - override fun toString(): String { - return javaClass.simpleName - } - - companion object { - - private const val JACOCO_MERGED_FILENAME = "jacoco-merged.exec" - - private fun getReportPaths(context: SensorContext): Set { - val reportPaths = HashSet() - val config = context.config() - val fs = context.fileSystem() - for (reportPath in config.getStringArray(REPORT_PATHS_PROPERTY)) { - val report = fs.resolvePath(reportPath) - if (!report.isFile) { - if (config.hasKey(REPORT_PATHS_PROPERTY)) { - LOG.info("JaCoCo report not found: '{}'", reportPath) - } - } else { - reportPaths.add(report) - } - } - if (config.hasKey(REPORT_PATH_PROPERTY)) { - warnUsageOfDeprecatedProperty(config, REPORT_PATH_PROPERTY) - val report = fs.resolvePath(config.get(REPORT_PATH_PROPERTY).unwrap()!!) - if (!report.isFile) { - LOG.info("JaCoCo UT report not found: '{}'", config.get(REPORT_PATH_PROPERTY).unwrap()) - } else { - reportPaths.add(report) - } - } - if (config.hasKey(IT_REPORT_PATH_PROPERTY)) { - warnUsageOfDeprecatedProperty(config, IT_REPORT_PATH_PROPERTY) - val report = fs.resolvePath(config.get(IT_REPORT_PATH_PROPERTY).unwrap()!!) - if (!report.isFile) { - LOG.info("JaCoCo IT report not found: '{}'", config.get(IT_REPORT_PATH_PROPERTY).unwrap()) - } else { - reportPaths.add(report) - } - } - return reportPaths - } - - private fun warnUsageOfDeprecatedProperty(config: Configuration, reportPathProperty: String) { - if (!config.hasKey(REPORT_PATHS_PROPERTY)) { - LOG.warn( - "Property '{}' is deprecated. Please use '{}' instead.", - reportPathProperty, - REPORT_PATHS_PROPERTY - ) - } - } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJacocoReportAnalyzer.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJacocoReportAnalyzer.kt deleted file mode 100644 index 90b9e48..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJacocoReportAnalyzer.kt +++ /dev/null @@ -1,226 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2010-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.jacoco - -import com.google.common.collect.Maps -import io.gitlab.arturbosch.detekt.sonar.foundation.KotlinClasspath -import org.apache.commons.lang.StringUtils -import org.jacoco.core.analysis.ICounter -import org.jacoco.core.analysis.ISourceFileCoverage -import org.jacoco.core.data.ExecutionDataStore -import org.sonar.api.batch.fs.InputFile -import org.sonar.api.batch.sensor.SensorContext -import org.sonar.api.batch.sensor.coverage.CoverageType -import org.sonar.api.batch.sensor.coverage.NewCoverage -import org.sonar.plugins.jacoco.ExecutionDataVisitor -import org.sonar.plugins.jacoco.JaCoCoExtensions -import org.sonar.plugins.jacoco.JacocoReportReader -import org.sonar.plugins.java.api.JavaResourceLocator -import java.io.File -import java.util.ArrayList - -private const val NO_JACOCO_EXECUTION_DATA_MESSAGE = - "Project coverage is set to 0% as no JaCoCo execution data has been dumped: {}" -private const val NO_CLASS_FILES_MESSAGE = - "No JaCoCo analysis of project coverage can be done since there is no class files." - -private const val NO_INFORMATION_ABOUT_COVERAGE_DATA_MESSAGE = "No information about coverage per test." -private const val COVERAGE_PER_TEST_MESSAGE = "Information about coverage per test has been collected." - -private const val NO_DATA_COLLECTED_MESSAGE = - "Coverage information was not collected. Perhaps you forget to include debug information into compiled classes?" - -@Suppress("ALL") -class KotlinJacocoReportAnalyzer @JvmOverloads constructor( - private val javaResourceLocator: JavaResourceLocator, - private val kotlinClasspath: KotlinClasspath, - private val readCoveragePerTests: Boolean = true, - private val report: File -) { - - private var classFilesCache: MutableMap = Maps.newHashMap() - - private fun fullyQualifiedClassName(packageName: String, simpleClassName: String): String = - if ("" == packageName) "" - else packageName + "/" + StringUtils.substringBeforeLast(simpleClassName, ".") - - private fun getResource(coverage: ISourceFileCoverage): InputFile? { - val className = fullyQualifiedClassName(coverage.packageName, coverage.name) - - // Do not save measures on resource which doesn't exist in the context - val inputFile = javaResourceLocator.findResourceByClassName(className) ?: return null - return if (inputFile.type() == InputFile.Type.TEST) { - null - } else { - inputFile - } - } - - fun analyse(context: SensorContext) { - for (classesDir in kotlinClasspath.binaryDirs) { - populateClassFilesCache(classesDir, "") - } - - if (classFilesCache.isEmpty()) { - JaCoCoExtensions.LOG.info(NO_CLASS_FILES_MESSAGE) - return - } - val jacocoExecutionData = report - readExecutionData(jacocoExecutionData, context) - - classFilesCache = Maps.newHashMap() - } - - private fun populateClassFilesCache(dir: File, path: String) { - val files = dir.listFiles() ?: return - for (file in files) { - if (file.isDirectory) { - populateClassFilesCache(file, path + file.name + "/") - } else if (file.name.endsWith(".class")) { - val className = path + StringUtils.removeEnd(file.name, ".class") - classFilesCache[className] = file - } - } - } - - private fun readExecutionData(jacocoExecutionData: File?, context: SensorContext) { - var newJacocoExecutionData = jacocoExecutionData - if (newJacocoExecutionData == null || !newJacocoExecutionData.isFile) { - JaCoCoExtensions.LOG.info(NO_JACOCO_EXECUTION_DATA_MESSAGE, newJacocoExecutionData) - newJacocoExecutionData = null - } - - val executionDataVisitor = ExecutionDataVisitor() - val jacocoReportReader = JacocoReportReader(newJacocoExecutionData) - .readJacocoReport(executionDataVisitor, executionDataVisitor) - - val collectedCoveragePerTest = readCoveragePerTests(executionDataVisitor, jacocoReportReader) - - val coverageBuilder = jacocoReportReader!!.analyzeFiles( - executionDataVisitor.merged, classFilesCache.values) - - var analyzedResources = 0 - for (coverage in coverageBuilder.sourceFiles) { - val inputFile = getResource(coverage) - if (inputFile != null) { - val newCoverage = context.newCoverage().onFile(inputFile).ofType(CoverageType.UNIT) - analyzeFile(newCoverage, inputFile, coverage) - newCoverage.save() - analyzedResources++ - } - } - - when { - analyzedResources == 0 -> JaCoCoExtensions.LOG.warn(NO_DATA_COLLECTED_MESSAGE) - collectedCoveragePerTest -> JaCoCoExtensions.LOG.info(COVERAGE_PER_TEST_MESSAGE) - newJacocoExecutionData != null -> JaCoCoExtensions.LOG.info(NO_INFORMATION_ABOUT_COVERAGE_DATA_MESSAGE) - } - } - - private fun readCoveragePerTests( - executionDataVisitor: ExecutionDataVisitor, - jacocoReportReader: JacocoReportReader - ): Boolean { - var collectedCoveragePerTest = false - if (readCoveragePerTests) { - for ((key, value) in executionDataVisitor.sessions) { - if (analyzeLinesCoveredByTests(key, value, jacocoReportReader)) { - collectedCoveragePerTest = true - } - } - } - return collectedCoveragePerTest - } - - private fun analyzeLinesCoveredByTests( - sessionId: String, - executionDataStore: ExecutionDataStore, - jacocoReportReader: JacocoReportReader - ): Boolean { - val i = sessionId.indexOf(' ') - if (i < 0) { - return false - } - - var result = false - val coverageBuilder = jacocoReportReader.analyzeFiles( - executionDataStore, classFilesOfStore(executionDataStore)) - for (coverage in coverageBuilder.sourceFiles) { - val resource = getResource(coverage) - if (resource != null) { - val coveredLines = coveredLines(coverage) - if (coveredLines.isNotEmpty()) { - result = true - } - } - } - return result - } - - private fun classFilesOfStore(executionDataStore: ExecutionDataStore): Collection { - return executionDataStore.contents - .map { it.name } - .mapNotNullTo(ArrayList()) { classFilesCache[it] } - } - - private fun coveredLines(coverage: ISourceFileCoverage): List { - val coveredLines = ArrayList() - lines@ for (lineId in coverage.firstLine..coverage.lastLine) { - val line = coverage.getLine(lineId) - when (line.instructionCounter.status) { - ICounter.FULLY_COVERED, ICounter.PARTLY_COVERED -> coveredLines.add(lineId) - ICounter.NOT_COVERED -> { - } - else -> continue@lines - } - } - return coveredLines - } - - private fun analyzeFile(newCoverage: NewCoverage, resource: InputFile, coverage: ISourceFileCoverage) { - JaCoCoExtensions.LOG.info("Analyzing file: {}//{}", resource.relativePath(), coverage.name) - var lineId = coverage.firstLine - statuses@ while (lineId <= coverage.lastLine && resource.lines() >= lineId) { - val hits: Int - val line = coverage.getLine(lineId) - hits = when (line.instructionCounter.status) { - ICounter.FULLY_COVERED, ICounter.PARTLY_COVERED -> 1 - ICounter.NOT_COVERED -> 0 - ICounter.EMPTY -> { - lineId++ - continue@statuses - } - else -> { - JaCoCoExtensions.LOG.warn("Unknown status for line {} in {}", lineId, resource) - lineId++ - continue@statuses - } - } - newCoverage.lineHits(lineId, hits) - val branchCounter = line.branchCounter - val conditions = branchCounter.totalCount - if (conditions > 0) { - val coveredConditions = branchCounter.coveredCount - newCoverage.conditions(lineId, conditions, coveredConditions) - } - lineId++ - } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJavaResourceLocator.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJavaResourceLocator.kt deleted file mode 100755 index 2a25fa2..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJavaResourceLocator.kt +++ /dev/null @@ -1,29 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.jacoco - -import io.gitlab.arturbosch.detekt.sonar.foundation.FILE_SUFFIX -import io.gitlab.arturbosch.detekt.sonar.foundation.KEY -import org.sonar.api.batch.fs.FileSystem -import org.sonar.api.batch.fs.InputFile -import org.sonar.plugins.java.api.JavaResourceLocator - -/** - * Locate kotlin or java input file for given class name. - */ -@Suppress("ALL") -class KotlinJavaResourceLocator( - private val javaResourceLocator: JavaResourceLocator, - private val fileSystem: FileSystem -) : JavaResourceLocator by javaResourceLocator { - - override fun findResourceByClassName(className: String): InputFile? { - return kotlinResource(className) ?: javaResourceLocator.findResourceByClassName(className) - } - - private fun kotlinResource(className: String): InputFile? { - val filePredicates = fileSystem.predicates() - return fileSystem.inputFile(filePredicates.and( - filePredicates.matchesPathPattern("**/" + className.replace('.', '/') + FILE_SUFFIX), - filePredicates.hasLanguage(KEY), - filePredicates.hasType(InputFile.Type.MAIN))) - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/package-info.java b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/package-info.java deleted file mode 100644 index 51ef384..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * JaCoCo support adapted from sonarqube-java-plugin. - */ -package io.gitlab.arturbosch.detekt.sonar.jacoco; diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRuleKey.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRuleKey.kt index 8b42a0a..f119113 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRuleKey.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRuleKey.kt @@ -1,22 +1,19 @@ package io.gitlab.arturbosch.detekt.sonar.rules -import io.gitlab.arturbosch.detekt.api.BaseRule import io.gitlab.arturbosch.detekt.api.Config import io.gitlab.arturbosch.detekt.api.Issue import io.gitlab.arturbosch.detekt.api.MultiRule import io.gitlab.arturbosch.detekt.api.Rule import io.gitlab.arturbosch.detekt.api.RuleSetProvider -import io.gitlab.arturbosch.detekt.api.YamlConfig -import io.gitlab.arturbosch.detekt.cli.ClasspathResourceConverter -import io.gitlab.arturbosch.detekt.sonar.foundation.DETEKT_REPOSITORY +import io.gitlab.arturbosch.detekt.api.internal.BaseRule +import io.gitlab.arturbosch.detekt.cli.loadDefaultConfig +import io.gitlab.arturbosch.detekt.sonar.foundation.REPOSITORY_KEY import org.sonar.api.rule.RuleKey import java.util.ServiceLoader -val defaultYamlConfig = YamlConfig.loadResource( - ClasspathResourceConverter().convert("default-detekt-config.yml") -) +val defaultConfig: Config = loadDefaultConfig() -val allLoadedRules = ServiceLoader.load(RuleSetProvider::class.java, Config::javaClass.javaClass.classLoader) +val allLoadedRules: List = ServiceLoader.load(RuleSetProvider::class.java, Config::class.java.classLoader) .flatMap { loadRules(it) } .flatMap { (it as? MultiRule)?.rules ?: listOf(it) } .asSequence() @@ -24,13 +21,13 @@ val allLoadedRules = ServiceLoader.load(RuleSetProvider::class.java, Config::jav .toList() private fun loadRules(provider: RuleSetProvider): List { - val subConfig = defaultYamlConfig.subConfig(provider.ruleSetId) + val subConfig = defaultConfig.subConfig(provider.ruleSetId) return provider.instance(subConfig).rules } -val ruleKeys = allLoadedRules.map { defineRuleKey(it) } +val ruleKeys: List = allLoadedRules.map { defineRuleKey(it) } -val ruleKeyLookup = ruleKeys.map { it.ruleKey to it }.toMap() +val ruleKeyLookup: Map = ruleKeys.associateBy { it.ruleKey } data class DetektRuleKey( private val repositoryKey: String, @@ -47,9 +44,10 @@ data class DetektRuleKey( if (other?.javaClass != javaClass && other?.javaClass != RuleKey::class.java) return false - val ruleKey = other as RuleKey? - return repository() == ruleKey!!.repository() && rule() == ruleKey.rule() + val ruleKey = other as RuleKey + return repository() == ruleKey.repository() && rule() == ruleKey.rule() } } -private fun defineRuleKey(rule: Rule) = DetektRuleKey(DETEKT_REPOSITORY, rule.ruleId, rule.active, rule.issue) +private fun defineRuleKey(rule: Rule): DetektRuleKey = + DetektRuleKey(REPOSITORY_KEY, rule.ruleId, rule.active, rule.issue) diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRulesDefinition.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRulesDefinition.kt index d49e544..fe21662 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRulesDefinition.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRulesDefinition.kt @@ -2,22 +2,22 @@ package io.gitlab.arturbosch.detekt.sonar.rules import io.gitlab.arturbosch.detekt.api.Rule import io.gitlab.arturbosch.detekt.sonar.foundation.DETEKT_ANALYZER -import io.gitlab.arturbosch.detekt.sonar.foundation.DETEKT_REPOSITORY -import io.gitlab.arturbosch.detekt.sonar.foundation.KEY +import io.gitlab.arturbosch.detekt.sonar.foundation.REPOSITORY_KEY +import io.gitlab.arturbosch.detekt.sonar.foundation.LANGUAGE_KEY import org.sonar.api.rule.RuleStatus import org.sonar.api.server.rule.RulesDefinition class DetektRulesDefinition : RulesDefinition { override fun define(context: RulesDefinition.Context) { - context.createRepository(DETEKT_REPOSITORY, KEY) + context.createRepository(REPOSITORY_KEY, LANGUAGE_KEY) .setName(DETEKT_ANALYZER) .createRules() .done() } } -fun RulesDefinition.NewRepository.createRules() = +fun RulesDefinition.NewRepository.createRules(): RulesDefinition.NewRepository = apply { allLoadedRules.map { defineRule(it) } } private fun RulesDefinition.NewRepository.defineRule(rule: Rule) { diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/SeverityTranslations.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/SeverityTranslations.kt index c6d3946..146751e 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/SeverityTranslations.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/SeverityTranslations.kt @@ -2,7 +2,7 @@ package io.gitlab.arturbosch.detekt.sonar.rules import io.gitlab.arturbosch.detekt.api.Severity -val severityTranslations = mapOf( +val severityTranslations: Map = mapOf( Severity.CodeSmell to org.sonar.api.rule.Severity.MAJOR, Severity.Defect to org.sonar.api.rule.Severity.CRITICAL, Severity.Maintainability to org.sonar.api.rule.Severity.MAJOR, diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektConfiguration.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektConfiguration.kt index 42d6405..79fd9cc 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektConfiguration.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektConfiguration.kt @@ -1,17 +1,14 @@ package io.gitlab.arturbosch.detekt.sonar.sensor import io.gitlab.arturbosch.detekt.api.Config -import io.gitlab.arturbosch.detekt.api.internal.FailFastConfig import io.gitlab.arturbosch.detekt.api.internal.PathFilters import io.gitlab.arturbosch.detekt.cli.CliArgs import io.gitlab.arturbosch.detekt.cli.loadConfiguration import io.gitlab.arturbosch.detekt.core.ProcessingSettings import io.gitlab.arturbosch.detekt.sonar.foundation.CONFIG_PATH_KEY -import io.gitlab.arturbosch.detekt.sonar.foundation.NoAutoCorrectConfig import io.gitlab.arturbosch.detekt.sonar.foundation.PATH_FILTERS_DEFAULTS import io.gitlab.arturbosch.detekt.sonar.foundation.PATH_FILTERS_KEY import io.gitlab.arturbosch.detekt.sonar.foundation.logger -import io.gitlab.arturbosch.detekt.sonar.rules.defaultYamlConfig import org.sonar.api.batch.sensor.SensorContext import org.sonar.api.config.Configuration import java.io.File @@ -24,7 +21,7 @@ fun createProcessingSettings(context: SensorContext): ProcessingSettings { val config = chooseConfig(baseDir, settings) return ProcessingSettings( inputPaths = listOf(baseDir.toPath()), - config = NoAutoCorrectConfig(config), + config = config, pathFilters = filters, outPrinter = System.out, errPrinter = System.err @@ -36,18 +33,11 @@ internal fun chooseConfig(baseDir: File, configuration: Configuration): Config { val possibleParseArguments = CliArgs().apply { config = externalConfigPath?.path + failFast = true // always use FailFast config to activate all detekt rules + autoCorrect = false // never change user files and conflict with sonar's reporting } - return possibleParseArguments.loadConfiguration().let { bestConfigMatch -> - // always use FailFast config to activate all detekt rules - // let the user decide through sonar's quality profiles which rules should not report instead - if (bestConfigMatch == Config.empty) { - logger.info("No detekt yaml configuration file found, using the default configuration.") - FailFastConfig(Config.empty, defaultYamlConfig) - } else { - FailFastConfig(bestConfigMatch, defaultYamlConfig) - } - } + return possibleParseArguments.loadConfiguration() } private fun tryFindDetektConfigurationFile(configuration: Configuration, baseDir: File): File? { diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektMetrics.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektMetrics.kt deleted file mode 100644 index b436993..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektMetrics.kt +++ /dev/null @@ -1,56 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.sensor - -import org.sonar.api.measures.CoreMetrics -import org.sonar.api.measures.Metric -import org.sonar.api.measures.Metrics - -class DetektMetrics : Metrics { - - override fun getMetrics(): MutableList> = mutableListOf( - projectLocMetric, - projectSlocMetric, - projectLlocMetric, - projectClocMetric, - projectComplexityMetric - ) -} - -val projectLocMetric: Metric = Metric.Builder("loc", - "Lines of Code", Metric.ValueType.INT) - .setDescription("Number of lines of code.") - .setDirection(Metric.DIRECTION_NONE) - .setQualitative(false) - .setDomain(CoreMetrics.DOMAIN_GENERAL) - .create() - -val projectSlocMetric: Metric = Metric.Builder("sloc", - "Source Lines of Code", Metric.ValueType.INT) - .setDescription("Number of source lines of code.") - .setDirection(Metric.DIRECTION_NONE) - .setQualitative(false) - .setDomain(CoreMetrics.DOMAIN_GENERAL) - .create() - -val projectLlocMetric: Metric = Metric.Builder("lloc", - "Logical Lines of Code", Metric.ValueType.INT) - .setDescription("Number of logical lines of code.") - .setDirection(Metric.DIRECTION_NONE) - .setQualitative(false) - .setDomain(CoreMetrics.DOMAIN_GENERAL) - .create() - -val projectClocMetric: Metric = Metric.Builder("cloc", - "Comment Lines of Code", Metric.ValueType.INT) - .setDescription("Number of comment lines of code.") - .setDirection(Metric.DIRECTION_NONE) - .setQualitative(false) - .setDomain(CoreMetrics.DOMAIN_GENERAL) - .create() - -val projectComplexityMetric: Metric = Metric.Builder("project_complexity", - "Project Cyclomatic Complexity", Metric.ValueType.INT) - .setDescription("Complexity of the whole project based on McCabe.") - .setDirection(Metric.DIRECTION_NONE) - .setQualitative(false) - .setDomain(CoreMetrics.DOMAIN_GENERAL) - .create() diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensor.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensor.kt index dfde462..cf7132d 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensor.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensor.kt @@ -1,10 +1,8 @@ package io.gitlab.arturbosch.detekt.sonar.sensor import io.gitlab.arturbosch.detekt.core.DetektFacade -import io.gitlab.arturbosch.detekt.core.FileProcessorLocator -import io.gitlab.arturbosch.detekt.core.RuleSetLocator import io.gitlab.arturbosch.detekt.sonar.foundation.DETEKT_SENSOR -import io.gitlab.arturbosch.detekt.sonar.foundation.KEY +import io.gitlab.arturbosch.detekt.sonar.foundation.LANGUAGE_KEY import org.sonar.api.batch.sensor.Sensor import org.sonar.api.batch.sensor.SensorContext import org.sonar.api.batch.sensor.SensorDescriptor @@ -12,18 +10,13 @@ import org.sonar.api.batch.sensor.SensorDescriptor class DetektSensor : Sensor { override fun describe(descriptor: SensorDescriptor) { - descriptor.name(DETEKT_SENSOR).onlyOnLanguage(KEY) + descriptor.name(DETEKT_SENSOR).onlyOnLanguage(LANGUAGE_KEY) } override fun execute(context: SensorContext) { val settings = createProcessingSettings(context) - val providers = RuleSetLocator(settings).load() - val ktFilesListener = ReturnKtFilesAnalysisEndsListener() - val processors = FileProcessorLocator(settings).load() + ktFilesListener - val facade = DetektFacade.create(settings, providers, processors) + val facade = DetektFacade.create(settings) val result = facade.run() IssueReporter(result, context).run() - ProjectMeasurementStorage(result, context).run() - FileProcessor(context, ktFilesListener.kotlinFiles).run() } } diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/FileMeasurementStorage.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/FileMeasurementStorage.kt deleted file mode 100644 index 6254661..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/FileMeasurementStorage.kt +++ /dev/null @@ -1,41 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.sensor - -import io.gitlab.arturbosch.detekt.core.processors.commentLinesKey -import io.gitlab.arturbosch.detekt.core.processors.complexityKey -import io.gitlab.arturbosch.detekt.core.processors.sourceLinesKey -import org.jetbrains.kotlin.com.intellij.openapi.util.Key -import org.jetbrains.kotlin.psi.KtFile -import org.sonar.api.batch.fs.InputComponent -import org.sonar.api.batch.sensor.SensorContext -import org.sonar.api.measures.CoreMetrics.COMMENT_LINES -import org.sonar.api.measures.CoreMetrics.COMPLEXITY -import org.sonar.api.measures.CoreMetrics.NCLOC -import org.sonar.api.measures.Metric - -/** - * Class responsible for processing individual [KtFile]s and extracting useful metrics. - */ -class FileMeasurementStorage(private val context: SensorContext) { - - fun save(file: KtFile, inputComponent: InputComponent) { - save(file, inputComponent, sourceLinesKey, NCLOC) - save(file, inputComponent, commentLinesKey, COMMENT_LINES) - save(file, inputComponent, complexityKey, COMPLEXITY) - } - - private fun save( - file: KtFile, - inputComponent: InputComponent, - dataKey: Key, - metricKey: Metric - ) { - val data = file.getUserData(dataKey) - if (data != null) { - context.newMeasure() - .withValue(data) - .forMetric(metricKey) - .on(inputComponent) - .save() - } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/FileProcessor.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/FileProcessor.kt deleted file mode 100644 index 7830cf7..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/FileProcessor.kt +++ /dev/null @@ -1,27 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.sensor - -import io.gitlab.arturbosch.detekt.api.internal.relativePath -import io.gitlab.arturbosch.detekt.sonar.foundation.KotlinSyntax -import org.jetbrains.kotlin.psi.KtFile -import org.sonar.api.batch.sensor.SensorContext - -class FileProcessor( - private val context: SensorContext, - private val ktFiles: List -) { - - private val fileStorage = FileMeasurementStorage(context) - private val fileSystem = context.fileSystem() - - fun run() { - val base = context.fileSystem().baseDir().toPath() - for (ktFile in ktFiles) { - fileSystem.inputFile { - base.fileName.resolve(it.relativePath()).toString() == ktFile.relativePath() - }?.let { - fileStorage.save(ktFile, it) - KotlinSyntax.processFile(it, ktFile, context) - } - } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/IssueReporter.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/IssueReporter.kt index 3df9fc6..2cbe18a 100644 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/IssueReporter.kt +++ b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/IssueReporter.kt @@ -5,7 +5,6 @@ import io.gitlab.arturbosch.detekt.api.Finding import io.gitlab.arturbosch.detekt.cli.baseline.BaselineFacade import io.gitlab.arturbosch.detekt.sonar.foundation.BASELINE_KEY import io.gitlab.arturbosch.detekt.sonar.foundation.logger -import io.gitlab.arturbosch.detekt.sonar.foundation.unwrap import io.gitlab.arturbosch.detekt.sonar.rules.ruleKeyLookup import org.sonar.api.batch.fs.InputFile import org.sonar.api.batch.sensor.SensorContext @@ -32,7 +31,7 @@ class IssueReporter( } private fun tryFindBaseline(config: Configuration, baseDir: File): BaselineFacade? { - return config.get(BASELINE_KEY).unwrap()?.let { path -> + fun createBaselineFacade(path: String): BaselineFacade? { logger.info("Registered baseline path: $path") var baselinePath = File(path) @@ -48,8 +47,11 @@ class IssueReporter( return null } } - BaselineFacade(baselinePath.toPath()) + return BaselineFacade(baselinePath.toPath()) } + return config.get(BASELINE_KEY) + .map(::createBaselineFacade) + .orElse(null) } private fun reportIssue(issue: Finding) { diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/ProjectMeasurementStorage.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/ProjectMeasurementStorage.kt deleted file mode 100644 index 1820afd..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/ProjectMeasurementStorage.kt +++ /dev/null @@ -1,36 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.sensor - -import io.gitlab.arturbosch.detekt.api.Detektion -import io.gitlab.arturbosch.detekt.core.processors.commentLinesKey -import io.gitlab.arturbosch.detekt.core.processors.complexityKey -import io.gitlab.arturbosch.detekt.core.processors.linesKey -import io.gitlab.arturbosch.detekt.core.processors.logicalLinesKey -import io.gitlab.arturbosch.detekt.core.processors.sourceLinesKey -import org.jetbrains.kotlin.com.intellij.openapi.util.Key -import org.sonar.api.batch.sensor.SensorContext -import org.sonar.api.measures.Metric - -class ProjectMeasurementStorage( - private val result: Detektion, - private val context: SensorContext -) { - - fun run() { - save(linesKey, projectLocMetric) - save(sourceLinesKey, projectSlocMetric) - save(logicalLinesKey, projectLlocMetric) - save(commentLinesKey, projectClocMetric) - save(complexityKey, projectComplexityMetric) - } - - private fun save(dataKey: Key, metricKey: Metric) { - val data = result.getData(dataKey) - if (data != null) { - context.newMeasure() - .withValue(data) - .forMetric(metricKey) - .on(context.module()) - .save() - } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/ReturnKtFilesAnalysisEndsListener.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/ReturnKtFilesAnalysisEndsListener.kt deleted file mode 100644 index 36a25f7..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/ReturnKtFilesAnalysisEndsListener.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.sensor - -import io.gitlab.arturbosch.detekt.api.Detektion -import io.gitlab.arturbosch.detekt.api.FileProcessListener -import io.gitlab.arturbosch.detekt.api.SingleAssign -import org.jetbrains.kotlin.psi.KtFile - -class ReturnKtFilesAnalysisEndsListener : FileProcessListener { - - var kotlinFiles: List by SingleAssign() - - override fun onFinish(files: List, result: Detektion) { - kotlinFiles = files - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/KotlinSurefireParser.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/KotlinSurefireParser.kt deleted file mode 100644 index cc3d577..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/KotlinSurefireParser.kt +++ /dev/null @@ -1,231 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2012-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.surefire - -import io.gitlab.arturbosch.detekt.sonar.foundation.FILE_SUFFIX -import io.gitlab.arturbosch.detekt.sonar.foundation.KEY -import io.gitlab.arturbosch.detekt.sonar.surefire.data.UnitTestClassReport -import io.gitlab.arturbosch.detekt.sonar.surefire.data.UnitTestIndex -import org.apache.commons.lang.StringUtils -import org.sonar.api.batch.ScannerSide -import org.sonar.api.batch.fs.FilePredicate -import org.sonar.api.batch.fs.FilePredicates -import org.sonar.api.batch.fs.FileSystem -import org.sonar.api.batch.fs.InputFile -import org.sonar.api.batch.sensor.SensorContext -import org.sonar.api.component.ResourcePerspectives -import org.sonar.api.measures.CoreMetrics -import org.sonar.api.measures.Metric -import org.sonar.api.test.MutableTestPlan -import org.sonar.api.test.TestCase -import org.sonar.api.utils.log.Loggers -import org.sonar.java.AnalysisException -import java.io.File -import java.io.Serializable -import java.util.ArrayList -import java.util.HashMap -import javax.xml.stream.XMLStreamException -import kotlin.math.max - -/** - * Adapted from sonar's java plugin and translated to kotlin. - */ -@ScannerSide -class KotlinSurefireParser( - private val perspectives: ResourcePerspectives, - private val fileSystem: FileSystem -) { - - fun collect(context: SensorContext, reportsDirs: List, reportDirSetByUser: Boolean) { - val xmlFiles = getReports(reportsDirs, reportDirSetByUser) - if (xmlFiles.isNotEmpty()) { - parseFiles(context, xmlFiles) - } - } - - private fun parseFiles(context: SensorContext, reports: List) { - val index = UnitTestIndex() - parseFiles(reports, index) - sanitize(index) - save(index, context) - } - - private fun save(index: UnitTestIndex, context: SensorContext) { - var negativeTimeTestNumber: Long = 0 - val indexByInputFile = mapToInputFile(index.indexByClassname) - for ((key, report) in indexByInputFile) { - if (report.tests > 0) { - negativeTimeTestNumber += report.negativeTimeTestNumber - save(report, key, context) - } - } - if (negativeTimeTestNumber > 0) { - LOGGER.warn( - "There is {} test(s) reported with negative time by surefire, total duration may not be accurate.", - negativeTimeTestNumber - ) - } - } - - private fun mapToInputFile( - indexByClassname: Map - ): Map { - val result = HashMap() - for ((className, index) in indexByClassname) { - val resource = getUnitTestResource(className, index) - if (resource != null) { - val report = (result as MutableMap) - .computeIfAbsent(resource) { UnitTestClassReport() } - // in case of repeated/parameterized tests (JUnit 5.x) we may end up with tests having the same name - index.results.forEach { report.add(it) } - } else { - LOGGER.debug("Resource not found: {}", className) - } - } - return result - } - - private fun save(report: UnitTestClassReport, inputFile: InputFile, context: SensorContext) { - val testsCount = report.tests - report.skipped - saveMeasure(context, inputFile, CoreMetrics.SKIPPED_TESTS, report.skipped) - saveMeasure(context, inputFile, CoreMetrics.TESTS, testsCount) - saveMeasure(context, inputFile, CoreMetrics.TEST_ERRORS, report.errors) - saveMeasure(context, inputFile, CoreMetrics.TEST_FAILURES, report.failures) - saveMeasure(context, inputFile, CoreMetrics.TEST_EXECUTION_TIME, report.durationMilliseconds) - saveResults(inputFile, report) - } - - private fun saveResults(testFile: InputFile, report: UnitTestClassReport) { - for (unitTestResult in report.results) { - val testPlan = perspectives.`as`(MutableTestPlan::class.java, testFile) - testPlan?.addTestCase(unitTestResult.name) - ?.setDurationInMs(max(unitTestResult.durationMilliseconds, 0)) - ?.setStatus(TestCase.Status.of(unitTestResult.status)) - ?.setMessage(unitTestResult.message) - ?.setStackTrace(unitTestResult.stackTrace) - } - } - - private fun getUnitTestResource(className: String, unitTestClassReport: UnitTestClassReport): InputFile? { - return findKotlinTestByClassname(className) - // fall back on testSuite class name - // (repeated and parameterized tests from JUnit 5.0 are using test name as classname) - // Should be fixed with JUnit 5.1, see: https://github.com/junit-team/junit5/issues/1182 - ?: unitTestClassReport.results - .asSequence() - .filter { it.testSuiteClassName != null } - .map { findKotlinTestByClassname(it.testSuiteClassName!!) } - .firstOrNull { it != null } - } - - private fun findKotlinTestByClassname(className: String): InputFile? { - val fileName = StringUtils.replace(className, ".", "/") - val predicates = fileSystem.predicates() - val fileNamePredicates = getFileNamePredicateFromSuffixes( - predicates, - fileName, - arrayOf(FILE_SUFFIX) - ) - val searchPredicate = predicates.and(predicates.and( - predicates.hasLanguage(KEY), - predicates.hasType(InputFile.Type.TEST) - ), fileNamePredicates) - return if (fileSystem.hasFiles(searchPredicate)) { - fileSystem.inputFiles(searchPredicate).iterator().next() - } else { - null - } - } - - private fun getFileNamePredicateFromSuffixes( - p: FilePredicates, - fileName: String, - suffixes: Array - ): FilePredicate { - val fileNamePredicates = ArrayList(suffixes.size) - for (suffix in suffixes) { - fileNamePredicates.add(p.matchesPathPattern("**/$fileName$suffix")) - } - return p.or(fileNamePredicates) - } - - companion object { - - private val LOGGER = Loggers.get(KotlinSurefireParser::class.java) - - private fun getReports(dirs: List, reportDirSetByUser: Boolean): List = - dirs.asSequence() - .map { getReports(it, reportDirSetByUser) } - .flatten() - .toList() - - private fun getReports(dir: File, reportDirSetByUser: Boolean): List { - if (!dir.isDirectory) { - if (reportDirSetByUser) { - LOGGER.error("Reports path not found or is not a directory: " + dir.absolutePath) - } - return emptyList() - } - var unitTestResultFiles = findXMLFilesStartingWith(dir, "TEST-") - if (unitTestResultFiles.isEmpty()) { - // maybe there's only a test suite result file - unitTestResultFiles = findXMLFilesStartingWith(dir, "TESTS-") - } - if (unitTestResultFiles.isEmpty()) { - LOGGER.warn("Reports path contains no files matching TEST-.*.xml : " + dir.absolutePath) - } - return unitTestResultFiles.toList() - } - - private fun findXMLFilesStartingWith(dir: File, fileNameStart: String): Array = - dir.listFiles { _, name -> name.startsWith(fileNameStart) && name.endsWith(".xml") } - ?: emptyArray() - - private fun parseFiles(reports: List, index: UnitTestIndex) { - val parser = StaxParser(index) - for (report in reports) { - try { - parser.parse(report) - } catch (e: XMLStreamException) { - throw AnalysisException("Fail to parse the Surefire report: $report", e) - } - } - } - - private fun sanitize(index: UnitTestIndex) { - for (classname in index.classnames) { - if (StringUtils.contains(classname, "$")) { - // Surefire reports classes whereas sonar supports files - val parentClassName = StringUtils.substringBefore(classname, "$") - index.merge(classname, parentClassName) - } - } - } - - private fun saveMeasure( - context: SensorContext, - inputFile: InputFile, - metric: Metric, - value: T - ) { - context.newMeasure().forMetric(metric).on(inputFile).withValue(value).save() - } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/KotlinSurefireSensor.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/KotlinSurefireSensor.kt deleted file mode 100644 index e6131fb..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/KotlinSurefireSensor.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2012-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.surefire - -import io.gitlab.arturbosch.detekt.sonar.foundation.KEY -import io.gitlab.arturbosch.detekt.sonar.surefire.api.SurefireUtils -import org.sonar.api.batch.DependedUpon -import org.sonar.api.batch.fs.FileSystem -import org.sonar.api.batch.sensor.Sensor -import org.sonar.api.batch.sensor.SensorContext -import org.sonar.api.batch.sensor.SensorDescriptor -import org.sonar.api.config.Configuration -import org.sonar.api.scan.filesystem.PathResolver -import org.sonar.api.utils.log.Loggers -import java.io.File - -/** - * Adapted from sonar's java plugin and translated to kotlin. - */ -@DependedUpon("surefire-java") -class KotlinSurefireSensor( - private val kotlinSurefireParser: KotlinSurefireParser, - private val configuration: Configuration, - private val fs: FileSystem, - private val pathResolver: PathResolver -) : Sensor { - - override fun describe(descriptor: SensorDescriptor) { - descriptor.onlyOnLanguage(KEY).name("KotlinSurefireSensor") - } - - override fun execute(context: SensorContext) { - val dir = SurefireUtils.getReportsDirectories(configuration, fs, pathResolver).distinct() - collect(context, dir) - } - - private fun collect(context: SensorContext, reportsDir: List) { - LOGGER.info("parsing {}", reportsDir) - kotlinSurefireParser.collect(context, reportsDir, - configuration.hasKey(SurefireUtils.SUREFIRE_REPORT_PATHS_PROPERTY) || - configuration.hasKey(SurefireUtils.SUREFIRE_REPORTS_PATH_PROPERTY)) - } - - override fun toString(): String { - return javaClass.simpleName - } - - companion object { - private val LOGGER = Loggers.get(KotlinSurefireSensor::class.java) - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/StaxParser.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/StaxParser.kt deleted file mode 100644 index 64eb107..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/StaxParser.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2012-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.surefire - -import com.ctc.wstx.stax.WstxInputFactory -import io.gitlab.arturbosch.detekt.sonar.surefire.data.SurefireStaxHandler -import io.gitlab.arturbosch.detekt.sonar.surefire.data.UnitTestIndex -import org.codehaus.staxmate.SMInputFactory -import org.codehaus.staxmate.`in`.SMHierarchicCursor -import java.io.File -import java.io.FileInputStream -import java.io.IOException -import javax.xml.stream.XMLInputFactory -import javax.xml.stream.XMLStreamException - -/** - * Adapted from sonar's java plugin and translated to kotlin. - */ -internal class StaxParser(index: UnitTestIndex) { - - private val inf: SMInputFactory - private val streamHandler: SurefireStaxHandler = SurefireStaxHandler(index) - - init { - val xmlFactory = XMLInputFactory.newInstance() - if (xmlFactory is WstxInputFactory) { - xmlFactory.configureForLowMemUsage() - xmlFactory.config.setUndeclaredEntityResolver { _: String, _: String, _: String, namespace: String -> - namespace - } - } - xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, false) - xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false) - xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false) - inf = SMInputFactory(xmlFactory) - } - - @Throws(XMLStreamException::class) - fun parse(xmlFile: File) { - try { - FileInputStream(xmlFile).use { input -> parse(inf.rootElementCursor(input)) } - } catch (e: IOException) { - throw XMLStreamException(e) - } - } - - @Throws(XMLStreamException::class) - private fun parse(rootCursor: SMHierarchicCursor) { - try { - streamHandler.stream(rootCursor) - } finally { - rootCursor.streamReader.closeCompletely() - } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/api/SurefireUtils.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/api/SurefireUtils.kt deleted file mode 100644 index fcfc8ea..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/api/SurefireUtils.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2012-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.surefire.api - -import org.sonar.api.batch.fs.FileSystem -import org.sonar.api.config.Configuration -import org.sonar.api.scan.filesystem.PathResolver -import org.sonar.api.utils.log.Loggers -import java.io.File - -/** - * Adapted from sonar's java plugin and translated to kotlin. - */ -object SurefireUtils { - - private val LOGGER = Loggers.get(SurefireUtils::class.java) - - const val SUREFIRE_REPORTS_PATH_PROPERTY = "sonar.junit.reportsPath" - const val SUREFIRE_REPORT_PATHS_PROPERTY = "sonar.junit.reportPaths" - - /** - * Find the directories containing the surefire reports. - * @param settings Analysis settings. - * @param fs FileSystem containing indexed files. - * @param pathResolver Path solver. - * @return The directories containing the surefire reports or - * default one (target/surefire-reports) if not found (not configured or not found). - */ - @Suppress("ReturnCount") - fun getReportsDirectories(settings: Configuration, fs: FileSystem, pathResolver: PathResolver): List { - val dir = getReportsDirectoryFromDeprecatedProperty(settings, fs, pathResolver) - val dirs = getReportsDirectoriesFromProperty(settings, fs, pathResolver) - if (dirs != null) { - if (dir != null) { - // both properties are set, deprecated property ignored - LOGGER.debug( - "Property '{}' is deprecated and will be ignored, as property '{}' is also set.", - SUREFIRE_REPORTS_PATH_PROPERTY, - SUREFIRE_REPORT_PATHS_PROPERTY - ) - } - return dirs - } - if (dir != null) { - LOGGER.info( - "Property '{}' is deprecated. Use property '{}' instead.", - SUREFIRE_REPORTS_PATH_PROPERTY, - SUREFIRE_REPORT_PATHS_PROPERTY - ) - return listOf(dir) - } - // both properties are not set - return listOf(File(fs.baseDir(), "target/surefire-reports")) - } - - private fun getReportsDirectoriesFromProperty( - settings: Configuration, - fs: FileSystem, - pathResolver: PathResolver - ): List? { - return if (settings.hasKey(SUREFIRE_REPORT_PATHS_PROPERTY)) { - settings.getStringArray(SUREFIRE_REPORT_PATHS_PROPERTY) - .asSequence() - .map { it.trim() } - .mapNotNull { getFileFromPath(fs, pathResolver, it) } - .toList() - } else { - null - } - } - - private fun getReportsDirectoryFromDeprecatedProperty( - settings: Configuration, - fs: FileSystem, - pathResolver: PathResolver - ): File? { - if (settings.hasKey(SUREFIRE_REPORTS_PATH_PROPERTY)) { - val path = settings.get(SUREFIRE_REPORTS_PATH_PROPERTY).orElse(null) - if (path != null) { - return getFileFromPath(fs, pathResolver, path) - } - } - return null - } - - @Suppress("TooGenericExceptionCaught") - private fun getFileFromPath(fs: FileSystem, pathResolver: PathResolver, path: String): File? { - try { - return pathResolver.relativeFile(fs.baseDir(), path) - } catch (e: Exception) { - // exceptions on file not found was only occurring with SQ 5.6 LTS, not with SQ 6.4 - LOGGER.info("Surefire report path: {}/{} not found.", fs.baseDir(), path) - } - return null - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/SurefireStaxHandler.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/SurefireStaxHandler.kt deleted file mode 100644 index 7b5a68d..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/SurefireStaxHandler.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2012-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.surefire.data - -import org.apache.commons.lang.StringUtils -import org.codehaus.staxmate.`in`.ElementFilter -import org.codehaus.staxmate.`in`.SMEvent -import org.codehaus.staxmate.`in`.SMHierarchicCursor -import org.codehaus.staxmate.`in`.SMInputCursor -import org.sonar.api.utils.ParsingUtils -import java.text.ParseException -import java.util.Locale -import javax.xml.stream.XMLStreamException - -/** - * Adapted from sonar's java plugin and translated to kotlin. - */ -class SurefireStaxHandler(private val index: UnitTestIndex) { - - @Throws(XMLStreamException::class) - fun stream(rootCursor: SMHierarchicCursor) { - val testSuite = rootCursor.constructDescendantCursor(ElementFilter("testsuite")) - var testSuiteEvent: SMEvent? - testSuiteEvent = testSuite.next - while (testSuiteEvent != null) { - if (testSuiteEvent.compareTo(SMEvent.START_ELEMENT) == 0) { - val testSuiteClassName = testSuite.getAttrValue("name") - if (StringUtils.contains(testSuiteClassName, "$")) { - // test suites for inner classes are ignored - return - } - parseTestCase(testSuiteClassName, testSuite.childCursor(ElementFilter("testcase"))) - } - testSuiteEvent = testSuite.next - } - } - - @Throws(XMLStreamException::class) - private fun parseTestCase(testSuiteClassName: String, testCase: SMInputCursor) { - var event: SMEvent? = testCase.next - while (event != null) { - if (event.compareTo(SMEvent.START_ELEMENT) == 0) { - val testClassName = getClassname(testCase, testSuiteClassName) - val classReport = index.index(testClassName) - parseTestCase(testCase, testSuiteClassName, classReport) - } - event = testCase.next - } - } - - @Throws(XMLStreamException::class) - private fun getClassname(testCaseCursor: SMInputCursor, defaultClassname: String): String { - var testClassName = testCaseCursor.getAttrValue("classname") - if (StringUtils.isNotBlank(testClassName) && testClassName.endsWith(")")) { - testClassName = testClassName.substring(0, testClassName.indexOf('(')) - } - return StringUtils.defaultIfBlank(testClassName, defaultClassname) - } - - @Throws(XMLStreamException::class) - private fun parseTestCase(testCaseCursor: SMInputCursor, testSuiteClassName: String, report: UnitTestClassReport) { - report.add(parseTestResult(testCaseCursor, testSuiteClassName)) - } - - @Throws(XMLStreamException::class) - private fun setStackAndMessage(result: UnitTestResult, stackAndMessageCursor: SMInputCursor) { - result.message = stackAndMessageCursor.getAttrValue("message") - val stack = stackAndMessageCursor.collectDescendantText() - result.stackTrace = stack - } - - @Throws(XMLStreamException::class) - private fun parseTestResult(testCaseCursor: SMInputCursor, testSuiteClassName: String): UnitTestResult { - val detail = UnitTestResult() - val name = getTestCaseName(testCaseCursor) - detail.name = name - detail.testSuiteClassName = testSuiteClassName - - var status = UnitTestResult.STATUS_OK - val time = testCaseCursor.getAttrValue("time") - var duration: Long? = null - - val childNode = testCaseCursor.descendantElementCursor() - if (childNode.next != null) { - when (childNode.localName) { - "skipped" -> { - status = UnitTestResult.STATUS_SKIPPED - // bug with surefire reporting wrong time for skipped tests - duration = 0L - } - "failure" -> { - status = UnitTestResult.STATUS_FAILURE - setStackAndMessage(detail, childNode) - } - "error" -> { - status = UnitTestResult.STATUS_ERROR - setStackAndMessage(detail, childNode) - } - } - } - while (childNode.next != null) { - // make sure we loop till the end of the elements cursor - } - if (duration == null) { - duration = getTimeAttributeInMS(time) - } - detail.durationMilliseconds = duration - detail.status = status - return detail - } - - @Suppress("MagicNumber") - @Throws(XMLStreamException::class) - private fun getTimeAttributeInMS(value: String): Long { - // hardcoded to Locale.ENGLISH see http://jira.codehaus.org/browse/SONAR-602 - try { - val time = ParsingUtils.parseNumber(value, Locale.ENGLISH) - return if (!time.isNaN()) { - ParsingUtils.scaleValue(time * 1000, 3).toLong() - } else { - 0L - } - } catch (e: ParseException) { - throw XMLStreamException(e) - } - } - - @Throws(XMLStreamException::class) - private fun getTestCaseName(testCaseCursor: SMInputCursor): String { - val classname = testCaseCursor.getAttrValue("classname") - val name = testCaseCursor.getAttrValue("name") - return if (StringUtils.contains(classname, "$")) { - StringUtils.substringAfter(classname, "$") + "/" + name - } else { - name - } - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestClassReport.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestClassReport.kt deleted file mode 100644 index 0b110e6..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestClassReport.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2012-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.surefire.data - -/** - * Adapted from sonar's java plugin and translated to kotlin. - */ -data class UnitTestClassReport( - var errors: Int = 0, - var failures: Int = 0, - var skipped: Int = 0, - var tests: Int = 0, - var durationMilliseconds: Long = 0L, - var negativeTimeTestNumber: Long = 0L, - val results: MutableList = mutableListOf() -) { - - fun add(other: UnitTestClassReport): UnitTestClassReport { - for (otherResult in other.results) { - add(otherResult) - } - return this - } - - fun add(result: UnitTestResult): UnitTestClassReport { - results.add(result) - when { - result.status == UnitTestResult.STATUS_SKIPPED -> skipped += 1 - result.status == UnitTestResult.STATUS_FAILURE -> failures += 1 - result.status == UnitTestResult.STATUS_ERROR -> errors += 1 - } - tests += 1 - if (result.durationMilliseconds < 0) { - negativeTimeTestNumber += 1 - } else { - durationMilliseconds += result.durationMilliseconds - } - return this - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestIndex.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestIndex.kt deleted file mode 100644 index 4fb14e6..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestIndex.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2012-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.surefire.data - -import com.google.common.collect.Maps -import com.google.common.collect.Sets - -/** - * Adapted from sonar's java plugin and translated to kotlin. - */ -class UnitTestIndex { - - val indexByClassname: MutableMap - val classnames: Set get() = Sets.newHashSet(indexByClassname.keys) - - init { - this.indexByClassname = Maps.newHashMap() - } - - fun index(classname: String): UnitTestClassReport { - return indexByClassname.computeIfAbsent(classname) { UnitTestClassReport() } - } - - operator fun get(classname: String): UnitTestClassReport? { - return indexByClassname[classname] - } - - fun merge(classname: String, intoClassname: String): UnitTestClassReport? { - val from = indexByClassname[classname] - if (from != null) { - val to = index(intoClassname) - to.add(from) - indexByClassname.remove(classname) - return to - } - return null - } -} diff --git a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestResult.kt b/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestResult.kt deleted file mode 100644 index 981933b..0000000 --- a/src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/surefire/data/UnitTestResult.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SonarQube Java - * Copyright (C) 2012-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * 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 io.gitlab.arturbosch.detekt.sonar.surefire.data - -/** - * Adapted from sonar's java plugin and translated to kotlin. - */ -@Suppress("unused") -data class UnitTestResult( - var name: String? = null, - var testSuiteClassName: String? = null, - var status: String? = null, - var stackTrace: String? = null, - var message: String? = null, - var durationMilliseconds: Long = 0L -) { - val isErrorOrFailure: Boolean get() = STATUS_ERROR == status || STATUS_FAILURE == status - - val isError: Boolean get() = STATUS_ERROR == status - - companion object { - const val STATUS_OK = "ok" - const val STATUS_ERROR = "error" - const val STATUS_FAILURE = "failure" - const val STATUS_SKIPPED = "skipped" - } -} diff --git a/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.FileProcessListener b/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.FileProcessListener deleted file mode 100644 index 6f2e12c..0000000 --- a/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.FileProcessListener +++ /dev/null @@ -1 +0,0 @@ -io.gitlab.arturbosch.detekt.sonar.sensor.ReturnKtFilesAnalysisEndsListener diff --git a/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/NoAutoCorrectConfigTest.kt b/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/NoAutoCorrectConfigTest.kt deleted file mode 100644 index 5c47a88..0000000 --- a/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/foundation/NoAutoCorrectConfigTest.kt +++ /dev/null @@ -1,65 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.foundation - -import io.gitlab.arturbosch.detekt.api.Config -import io.gitlab.arturbosch.detekt.api.YamlConfig -import io.mockk.every -import io.mockk.mockk -import org.assertj.core.api.Assertions.assertThat -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe -import java.io.ByteArrayInputStream -import java.net.URL - -class NoAutoCorrectConfigTest : Spek({ - - describe("a configuration") { - - context("with autoCorrect on 1st level") { - val config = NoAutoCorrectConfig( - createConfig(""" - autoCorrect: true - """.trimIndent()) - ) - - it("should be false") { - assertThat(config.valueOrDefault("autoCorrect", true)).isEqualTo(false) - } - } - - context("with autoCorrect on 2d level") { - val config = NoAutoCorrectConfig( - createConfig(""" - secondLevel: - autoCorrect: true - """.trimIndent()) - ) - - it("should be false") { - val secondLevelConfig = config.subConfig("secondLevel") - assertThat(secondLevelConfig.valueOrDefault("autoCorrect", true)).isEqualTo(false) - } - } - - context("with autoCorrect on 3rd level") { - val config = NoAutoCorrectConfig( - createConfig(""" - secondLevel: - thirdLevel: - autoCorrect: true - """.trimIndent()) - ) - - it("should be false") { - val thirdLevelConfig = config.subConfig("secondLevel").subConfig("thirdLevel") - assertThat(thirdLevelConfig.valueOrDefault("autoCorrect", true)).isEqualTo(false) - } - } - } -}) - -private fun createConfig(yamlInput: String): Config { - val yamlInputStream = ByteArrayInputStream(yamlInput.toByteArray(Charsets.UTF_8)) - val url = mockk() - every { url.openStream() } returns yamlInputStream - return YamlConfig.loadResource(url) -} diff --git a/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJavaResourceLocatorTest.kt b/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJavaResourceLocatorTest.kt deleted file mode 100644 index 1a875e8..0000000 --- a/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/jacoco/KotlinJavaResourceLocatorTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -package io.gitlab.arturbosch.detekt.sonar.jacoco - -import io.mockk.clearMocks -import io.mockk.every -import io.mockk.mockk -import org.assertj.core.api.Assertions.assertThat -import org.sonar.api.batch.fs.FilePredicate -import org.sonar.api.batch.fs.FilePredicates -import org.sonar.api.batch.fs.FileSystem -import org.sonar.api.batch.fs.InputFile -import org.sonar.plugins.java.api.JavaResourceLocator -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe - -const val className = "foo.Bar" - -class KotlinJavaResourceLocatorTest : Spek({ - - val javaLocator = mockk() - val fileSystem = mockk() - val predicates = mockk() - val predicate = mockk() - val kotlinFile = mockk(name = "Bar.kt") - val javaFile = mockk(name = "Bar.java") - - every { predicates.matchesPathPattern(any()) } returns predicate - every { predicates.and(any(), any(), any()) } returns predicate - every { predicates.hasLanguage(any()) } returns predicate - every { predicates.hasType(any()) } returns predicate - - describe("a locator") { - - val locator = KotlinJavaResourceLocator(javaLocator, fileSystem) - - beforeEach { - clearMocks(fileSystem) - every { fileSystem.predicates() } returns predicates - } - - context("kotlin file present") { - - it("should find kotlin resource") { - every { fileSystem.inputFile(any()) } returns kotlinFile - assertThat(locator.findResourceByClassName(className)).isEqualTo(kotlinFile) - } - } - - context("no kotlin file present") { - - it("should find java resource") { - every { fileSystem.inputFile(any()) } returns null - every { javaLocator.findResourceByClassName(className) } returns javaFile - assertThat(locator.findResourceByClassName(className)).isEqualTo(javaFile) - } - - it("should return null if no java resource") { - every { fileSystem.inputFile(any()) } returns null - every { javaLocator.findResourceByClassName(className) } returns null - assertThat(locator.findResourceByClassName(className)).isNull() - } - } - } -}) diff --git a/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensorTest.kt b/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensorTest.kt index 1459afc..f4f63d7 100644 --- a/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensorTest.kt +++ b/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensorTest.kt @@ -1,6 +1,6 @@ package io.gitlab.arturbosch.detekt.sonar.sensor -import io.gitlab.arturbosch.detekt.sonar.foundation.KEY +import io.gitlab.arturbosch.detekt.sonar.foundation.LANGUAGE_KEY import io.gitlab.arturbosch.detekt.sonar.foundation.PATH_FILTERS_KEY import io.mockk.every import io.mockk.mockk @@ -8,13 +8,10 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.sonar.api.batch.fs.internal.DefaultFileSystem -import org.sonar.api.batch.fs.internal.DefaultInputDir +import org.sonar.api.batch.fs.internal.DefaultInputFile import org.sonar.api.batch.fs.internal.TestInputFileBuilder import org.sonar.api.batch.sensor.internal.SensorContextTester import org.sonar.api.config.internal.MapSettings -import org.sonar.api.measures.CoreMetrics.COMMENT_LINES -import org.sonar.api.measures.CoreMetrics.COMPLEXITY -import org.sonar.api.measures.CoreMetrics.NCLOC import org.sonar.api.measures.FileLinesContext import org.sonar.api.measures.FileLinesContextFactory import java.io.File @@ -34,8 +31,8 @@ class DetektSensorTest { @Before fun setUp() { // Recreating all mutable objects to avoid retaining states across tests - context = SensorContextTester.create(resourcesDir).setSettings(settings) - fileSystem = context.fileSystem().add(DefaultInputDir("", "")) + context = SensorContextTester.create(resourcesDir.absoluteFile).setSettings(settings) + fileSystem = context.fileSystem() sensor = DetektSensor() fileLinesContextFactory = mockk() @@ -45,38 +42,23 @@ class DetektSensorTest { } @Test - fun `measures a single kotlin file`() { - val kotlinFileKey = addMockFile("KotlinFile.kt") + fun `executes detekt`() { + val file = addMockFile("KotlinFile.kt") sensor.execute(context) + val issues = context.allIssues().filter { it.primaryLocation().inputComponent() == file } - assertThat(context.measure(kotlinFileKey, NCLOC).value()).isEqualTo(2) - assertThat(context.measure(kotlinFileKey, COMMENT_LINES).value()).isEqualTo(0) + assertThat(issues).hasSize(7) } - @Test - fun `measures two classes`() { - val a = addMockFile("a/AClassOne.kt") - val b = addMockFile("b/BClassTwo.kt") - - sensor.execute(context) - - assertThat(context.measure(a, NCLOC).value()).isEqualTo(9) - assertThat(context.measure(a, COMMENT_LINES).value()).isEqualTo(3) - assertThat(context.measure(a, COMPLEXITY).value()).isEqualTo(1) - assertThat(context.measure(b, NCLOC).value()).isEqualTo(6) - assertThat(context.measure(b, COMMENT_LINES).value()).isEqualTo(3) - assertThat(context.measure(b, COMPLEXITY).value()).isEqualTo(0) - } - - private fun addMockFile(filePath: String): String { + private fun addMockFile(filePath: String): DefaultInputFile { val sourceFile = File(sourceDir, filePath) val kotlinFile = TestInputFileBuilder(RESOURCES_PATH, "$KOTLIN_PATH/$filePath") - .setLanguage(KEY) + .setLanguage(LANGUAGE_KEY) .initMetadata(sourceFile.readText()) .build() fileSystem.add(kotlinFile) - return kotlinFile.key() + return kotlinFile } companion object { diff --git a/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/LoadConfigSpec.kt b/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/LoadConfigSpec.kt index 92431c7..a49a813 100644 --- a/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/LoadConfigSpec.kt +++ b/src/test/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/LoadConfigSpec.kt @@ -1,8 +1,8 @@ package io.gitlab.arturbosch.detekt.sonar.sensor import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.internal.DisabledAutoCorrectConfig import io.gitlab.arturbosch.detekt.sonar.foundation.CONFIG_PATH_KEY -import io.gitlab.arturbosch.detekt.sonar.rules.defaultYamlConfig import org.assertj.core.api.Assertions.assertThat import org.sonar.api.config.internal.MapSettings import org.spekframework.spek2.Spek @@ -34,10 +34,10 @@ class LoadConfigSpec : Spek({ assertThat(config).isNotEqualTo(Config.empty) } - it("should default to default config") { + it("should default to disabled auto correct default detekt config") { val config = chooseConfig(base, MapSettings().asConfig()) - assertThat(config == defaultYamlConfig) + assertThat(config).isInstanceOf(DisabledAutoCorrectConfig::class.java) } } }) diff --git a/src/test/resources/kotlin/KotlinFile.kt b/src/test/resources/kotlin/KotlinFile.kt index 4fce211..0a2ac2b 100644 --- a/src/test/resources/kotlin/KotlinFile.kt +++ b/src/test/resources/kotlin/KotlinFile.kt @@ -1,3 +1,11 @@ package kotlin -const val JUST_A_CONST = 1 +private const val JUST_A_CONST = 1 + +private class KotlinFile( + +) { + +} + +fun f() = 5