Skip to content
This repository was archived by the owner on Jan 6, 2024. It is now read-only.

Commit 4a3972b

Browse files
authored
Use tooling module instead of relying on core and cli modules (#125)
Use version 1.10.0 of the maven detekt plugin
1 parent 11f9c01 commit 4a3972b

File tree

9 files changed

+184
-145
lines changed

9 files changed

+184
-145
lines changed

pom.xml

+9-12
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66
<groupId>io.github.detekt</groupId>
77
<artifactId>sonar-detekt</artifactId>
8-
<version>2.1.0</version>
8+
<version>2.2.0</version>
99
<url>https://github.com/detekt/sonar-kotlin</url>
1010

1111
<licenses>
@@ -20,8 +20,8 @@
2020

2121
<properties>
2222
<kotlin.version>1.3.72</kotlin.version>
23-
<spek.version>2.0.10</spek.version>
24-
<detekt.version>1.9.1</detekt.version>
23+
<spek.version>2.0.12</spek.version>
24+
<detekt.version>1.11.0-RC2</detekt.version>
2525
<sonar.api.version>7.9.3</sonar.api.version>
2626
<assertj.version>3.16.1</assertj.version>
2727
<jcommander.version>1.78</jcommander.version>
@@ -65,7 +65,7 @@
6565
</dependency>
6666
<dependency>
6767
<groupId>io.gitlab.arturbosch.detekt</groupId>
68-
<artifactId>detekt-cli</artifactId>
68+
<artifactId>detekt-tooling</artifactId>
6969
<version>${detekt.version}</version>
7070
</dependency>
7171
<dependency>
@@ -87,18 +87,12 @@
8787
<groupId>org.jetbrains.kotlin</groupId>
8888
<artifactId>kotlin-compiler-embeddable</artifactId>
8989
<version>${kotlin.version}</version>
90-
<scope>compile</scope>
9190
</dependency>
9291
<dependency>
9392
<groupId>org.jetbrains.kotlin</groupId>
9493
<artifactId>kotlin-stdlib-jdk8</artifactId>
9594
<version>${kotlin.version}</version>
9695
</dependency>
97-
<dependency>
98-
<groupId>com.beust</groupId>
99-
<artifactId>jcommander</artifactId>
100-
<version>${jcommander.version}</version>
101-
</dependency>
10296
<dependency>
10397
<groupId>org.jetbrains.kotlin</groupId>
10498
<artifactId>kotlin-test-junit</artifactId>
@@ -139,7 +133,7 @@
139133
<plugin>
140134
<groupId>org.sonarsource.sonar-packaging-maven-plugin</groupId>
141135
<artifactId>sonar-packaging-maven-plugin</artifactId>
142-
<version>1.18.0.372</version>
136+
<version>1.19.0.397</version>
143137
<extensions>true</extensions>
144138
<configuration>
145139
<pluginKey>detekt</pluginKey>
@@ -164,6 +158,9 @@
164158
<goal>compile</goal>
165159
</goals>
166160
<configuration>
161+
<args>
162+
<arg>-Xopt-in=kotlin.RequiresOptIn</arg>
163+
</args>
167164
<sourceDirs>
168165
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
169166
</sourceDirs>
@@ -235,7 +232,7 @@
235232
<plugin>
236233
<groupId>com.github.ozsie</groupId>
237234
<artifactId>detekt-maven-plugin</artifactId>
238-
<version>1.9.1</version>
235+
<version>1.10.0</version>
239236
<executions>
240237
<execution>
241238
<phase>verify</phase>

src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRuleKey.kt

+21-17
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,47 @@
11
package io.gitlab.arturbosch.detekt.sonar.rules
22

3+
import io.github.detekt.tooling.api.DefaultConfigurationProvider
34
import io.gitlab.arturbosch.detekt.api.Config
45
import io.gitlab.arturbosch.detekt.api.Issue
56
import io.gitlab.arturbosch.detekt.api.MultiRule
67
import io.gitlab.arturbosch.detekt.api.Rule
78
import io.gitlab.arturbosch.detekt.api.RuleSetProvider
89
import io.gitlab.arturbosch.detekt.api.internal.BaseRule
9-
import io.gitlab.arturbosch.detekt.cli.loadDefaultConfig
1010
import io.gitlab.arturbosch.detekt.sonar.foundation.REPOSITORY_KEY
1111
import org.sonar.api.rule.RuleKey
1212
import java.util.ServiceLoader
1313

14-
val defaultConfig: Config = loadDefaultConfig()
14+
internal val defaultConfig: Config = DefaultConfigurationProvider.load().get()
1515

16-
val excludedDuplicates = setOf(
17-
"Filename", // from KtLint; same as MatchingDeclarationName
18-
"MaximumLineLength", // from KtLint; same as MaxLineLength
19-
"NoUnitReturn", // from KtLint; same as OptionalUnit
20-
"NoWildcardImports" // from KtLint; same as WildcardImport
16+
/**
17+
* Exclude similar or duplicated rule implementations from other rule sets than the default one.
18+
*/
19+
internal val excludedDuplicates = setOf(
20+
"Filename", // MatchingDeclarationName
21+
"MaximumLineLength", // MaxLineLength
22+
"NoUnitReturn", // OptionalUnit
23+
"NoWildcardImports" // WildcardImport
2124
)
2225

23-
val allLoadedRules: List<Rule> = ServiceLoader.load(RuleSetProvider::class.java, Config::class.java.classLoader)
24-
.asSequence()
25-
.flatMap { loadRules(it).asSequence() }
26-
.flatMap { (it as? MultiRule)?.rules?.asSequence() ?: sequenceOf(it) }
27-
.filterIsInstance<Rule>()
28-
.filterNot { it.ruleId in excludedDuplicates }
29-
.toList()
26+
internal val allLoadedRules: List<Rule> =
27+
ServiceLoader.load(RuleSetProvider::class.java, Config::class.java.classLoader)
28+
.asSequence()
29+
.flatMap { loadRules(it).asSequence() }
30+
.flatMap { (it as? MultiRule)?.rules?.asSequence() ?: sequenceOf(it) }
31+
.filterIsInstance<Rule>()
32+
.filterNot { it.ruleId in excludedDuplicates }
33+
.toList()
3034

3135
private fun loadRules(provider: RuleSetProvider): List<BaseRule> {
3236
val subConfig = defaultConfig.subConfig(provider.ruleSetId)
3337
return provider.instance(subConfig).rules
3438
}
3539

36-
val ruleKeys: List<DetektRuleKey> = allLoadedRules.map { defineRuleKey(it) }
40+
internal val ruleKeys: List<DetektRuleKey> = allLoadedRules.map { defineRuleKey(it) }
3741

38-
val ruleKeyLookup: Map<String, DetektRuleKey> = ruleKeys.associateBy { it.ruleKey }
42+
internal val ruleKeyLookup: Map<String, DetektRuleKey> = ruleKeys.associateBy { it.ruleKey }
3943

40-
data class DetektRuleKey(
44+
internal data class DetektRuleKey(
4145
private val repositoryKey: String,
4246
val ruleKey: String,
4347
val active: Boolean,

src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/DetektRulesDefinition.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class DetektRulesDefinition : RulesDefinition {
1717
}
1818
}
1919

20-
fun RulesDefinition.NewRepository.createRules(): RulesDefinition.NewRepository =
20+
private fun RulesDefinition.NewRepository.createRules(): RulesDefinition.NewRepository =
2121
apply { allLoadedRules.map { defineRule(it) } }
2222

2323
private fun RulesDefinition.NewRepository.defineRule(rule: Rule) {

src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/rules/SeverityTranslations.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package io.gitlab.arturbosch.detekt.sonar.rules
22

33
import io.gitlab.arturbosch.detekt.api.Severity
44

5-
val severityTranslations: Map<Severity, String> = mapOf(
5+
internal val severityTranslations: Map<Severity, String> = mapOf(
66
Severity.CodeSmell to org.sonar.api.rule.Severity.MAJOR,
77
Severity.Defect to org.sonar.api.rule.Severity.CRITICAL,
88
Severity.Maintainability to org.sonar.api.rule.Severity.MAJOR,

src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektConfiguration.kt

+72-35
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,99 @@
11
package io.gitlab.arturbosch.detekt.sonar.sensor
22

3-
import io.gitlab.arturbosch.detekt.api.Config
4-
import io.gitlab.arturbosch.detekt.cli.CliArgs
5-
import io.gitlab.arturbosch.detekt.cli.createFilters
6-
import io.gitlab.arturbosch.detekt.cli.loadConfiguration
7-
import io.gitlab.arturbosch.detekt.core.ProcessingSettings
3+
import io.github.detekt.tooling.api.spec.ProcessingSpec
4+
import io.github.detekt.tooling.api.spec.RulesSpec
5+
import io.gitlab.arturbosch.detekt.sonar.foundation.BASELINE_KEY
86
import io.gitlab.arturbosch.detekt.sonar.foundation.CONFIG_PATH_KEY
97
import io.gitlab.arturbosch.detekt.sonar.foundation.PATH_FILTERS_DEFAULTS
108
import io.gitlab.arturbosch.detekt.sonar.foundation.PATH_FILTERS_KEY
119
import io.gitlab.arturbosch.detekt.sonar.foundation.logger
1210
import org.sonar.api.batch.sensor.SensorContext
1311
import org.sonar.api.config.Configuration
14-
import java.io.File
12+
import java.nio.file.Files
13+
import java.nio.file.Path
14+
import java.nio.file.Paths
1515

16-
fun createProcessingSettings(context: SensorContext): ProcessingSettings {
17-
val baseDir = context.fileSystem().baseDir()
16+
internal fun createSpec(context: SensorContext): ProcessingSpec {
17+
val baseDir = context.fileSystem().baseDir().toPath()
1818
val settings = context.config()
19-
val filters = CliArgs {
20-
excludes = settings.get(PATH_FILTERS_KEY).orElse(PATH_FILTERS_DEFAULTS)
21-
}.createFilters()
22-
val config = chooseConfig(baseDir, settings)
23-
return ProcessingSettings(
24-
inputPaths = listOf(baseDir.toPath()),
25-
config = config,
26-
pathFilters = filters,
27-
outPrinter = System.out,
28-
errPrinter = System.err
29-
)
19+
return createSpec(baseDir, settings)
3020
}
3121

32-
internal fun chooseConfig(baseDir: File, configuration: Configuration): Config {
33-
val externalConfigPath = tryFindDetektConfigurationFile(configuration, baseDir)
22+
internal fun createSpec(baseDir: Path, configuration: Configuration): ProcessingSpec {
23+
val configPath = tryFindDetektConfigurationFile(baseDir, configuration)
24+
val baselineFile = tryFindBaselineFile(baseDir, configuration)
3425

35-
val possibleParseArguments = CliArgs().apply {
36-
config = externalConfigPath?.path
37-
failFast = true // always use FailFast config to activate all detekt rules
38-
autoCorrect = false // never change user files and conflict with sonar's reporting
26+
return ProcessingSpec {
27+
project {
28+
basePath = baseDir
29+
inputPaths = listOf(baseDir)
30+
excludes = getProjectExcludeFilters(configuration)
31+
}
32+
rules {
33+
activateExperimentalRules = true // publish all; quality profiles will filter
34+
maxIssuePolicy = RulesSpec.MaxIssuePolicy.AllowAny
35+
autoCorrect = false // never change user files and conflict with sonar's reporting
36+
}
37+
config {
38+
useDefaultConfig = true
39+
configPaths = listOfNotNull(configPath)
40+
}
41+
baseline {
42+
path = baselineFile
43+
}
3944
}
45+
}
46+
47+
internal fun getProjectExcludeFilters(configuration: Configuration): List<String> =
48+
configuration.get(PATH_FILTERS_KEY)
49+
.orElse(PATH_FILTERS_DEFAULTS)
50+
.splitToSequence(",", ";")
51+
.map { it.trim() }
52+
.filter { it.isNotEmpty() }
53+
.toList()
54+
55+
internal fun tryFindBaselineFile(baseDir: Path, config: Configuration): Path? {
56+
fun createBaselineFacade(path: Path): Path? {
57+
logger.info("Registered baseline path: $path")
58+
var baselinePath = path
59+
60+
if (Files.notExists(baselinePath)) {
61+
baselinePath = baseDir.resolve(path)
62+
}
4063

41-
return possibleParseArguments.loadConfiguration()
64+
if (Files.notExists(baselinePath)) {
65+
val parentFile = baseDir.parent
66+
if (parentFile != null) {
67+
baselinePath = parentFile.resolve(path)
68+
} else {
69+
return null
70+
}
71+
}
72+
return baselinePath
73+
}
74+
return config.get(BASELINE_KEY)
75+
.map { Paths.get(it) }
76+
.map(::createBaselineFacade)
77+
.orElse(null)
4278
}
4379

44-
private fun tryFindDetektConfigurationFile(configuration: Configuration, baseDir: File): File? {
45-
return configuration.get(CONFIG_PATH_KEY).map { path ->
80+
private val supportedYamlEndings = setOf(".yaml", ".yml")
81+
82+
internal fun tryFindDetektConfigurationFile(baseDir: Path, configuration: Configuration): Path? =
83+
configuration.get(CONFIG_PATH_KEY).map { path ->
4684
logger.info("Registered config path: $path")
47-
var configFile = File(path)
85+
var configFile = Paths.get(path)
4886

49-
if (!configFile.exists() || configFile.endsWith(".yaml")) {
50-
configFile = File(baseDir.path, path)
87+
if (Files.notExists(configFile) || supportedYamlEndings.any { path.toString().endsWith(it) }) {
88+
configFile = baseDir.resolve(path)
5189
}
52-
if (!configFile.exists() || configFile.endsWith(".yaml")) {
53-
val parentFile = baseDir.parentFile
90+
if (Files.notExists(configFile) || supportedYamlEndings.any { path.toString().endsWith(it) }) {
91+
val parentFile = baseDir.parent
5492
if (parentFile != null) {
55-
configFile = File(parentFile.path, path)
93+
configFile = parentFile.resolve(path)
5694
} else {
5795
return@map null
5896
}
5997
}
6098
configFile
6199
}.orElse(null)
62-
}

src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/DetektSensor.kt

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package io.gitlab.arturbosch.detekt.sonar.sensor
22

3-
import io.gitlab.arturbosch.detekt.core.DetektFacade
3+
import io.github.detekt.tooling.api.AnalysisResult
4+
import io.github.detekt.tooling.api.DetektProvider
5+
import io.github.detekt.tooling.api.UnexpectedError
6+
import io.gitlab.arturbosch.detekt.api.UnstableApi
47
import io.gitlab.arturbosch.detekt.sonar.foundation.DETEKT_SENSOR
58
import io.gitlab.arturbosch.detekt.sonar.foundation.LANGUAGE_KEY
69
import org.sonar.api.batch.sensor.Sensor
@@ -13,10 +16,20 @@ class DetektSensor : Sensor {
1316
descriptor.name(DETEKT_SENSOR).onlyOnLanguage(LANGUAGE_KEY)
1417
}
1518

19+
@OptIn(UnstableApi::class)
1620
override fun execute(context: SensorContext) {
17-
val settings = createProcessingSettings(context)
18-
val facade = DetektFacade.create(settings)
21+
val spec = createSpec(context)
22+
val facade = DetektProvider.load().get(spec)
1923
val result = facade.run()
20-
IssueReporter(result, context).run()
24+
checkErrors(result)
25+
IssueReporter(checkNotNull(result.container), context).run()
26+
}
27+
28+
private fun checkErrors(result: AnalysisResult) {
29+
when (val error = result.error) {
30+
is UnexpectedError -> throw error.cause
31+
null -> return
32+
else -> throw error
33+
}
2134
}
2235
}

src/main/kotlin/io/gitlab/arturbosch/detekt/sonar/sensor/IssueReporter.kt

+1-32
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,12 @@ package io.gitlab.arturbosch.detekt.sonar.sensor
22

33
import io.gitlab.arturbosch.detekt.api.Detektion
44
import io.gitlab.arturbosch.detekt.api.Finding
5-
import io.gitlab.arturbosch.detekt.cli.baseline.BaselineFacade
6-
import io.gitlab.arturbosch.detekt.sonar.foundation.BASELINE_KEY
75
import io.gitlab.arturbosch.detekt.sonar.foundation.logger
86
import io.gitlab.arturbosch.detekt.sonar.rules.excludedDuplicates
97
import io.gitlab.arturbosch.detekt.sonar.rules.ruleKeyLookup
108
import org.sonar.api.batch.fs.InputFile
119
import org.sonar.api.batch.sensor.SensorContext
1210
import org.sonar.api.batch.sensor.issue.NewIssue
13-
import org.sonar.api.config.Configuration
14-
import java.io.File
1511

1612
class IssueReporter(
1713
private val result: Detektion,
@@ -20,41 +16,14 @@ class IssueReporter(
2016

2117
private val fileSystem = context.fileSystem()
2218
private val baseDir = fileSystem.baseDir()
23-
private val config = context.config()
2419

2520
fun run() {
26-
val baseline = tryFindBaseline(config, baseDir)
2721
for ((ruleSet, findings) in result.findings) {
2822
logger.info("RuleSet: $ruleSet - ${findings.size}")
29-
val filtered = baseline?.filter(findings) ?: findings
30-
filtered.forEach(this::reportIssue)
23+
findings.forEach(this::reportIssue)
3124
}
3225
}
3326

34-
private fun tryFindBaseline(config: Configuration, baseDir: File): BaselineFacade? {
35-
fun createBaselineFacade(path: String): BaselineFacade? {
36-
logger.info("Registered baseline path: $path")
37-
var baselinePath = File(path)
38-
39-
if (!baselinePath.exists()) {
40-
baselinePath = File(baseDir.path, path)
41-
}
42-
43-
if (!baselinePath.exists()) {
44-
val parentFile = baseDir.parentFile
45-
if (parentFile != null) {
46-
baselinePath = File(parentFile.path, path)
47-
} else {
48-
return null
49-
}
50-
}
51-
return BaselineFacade(baselinePath.toPath())
52-
}
53-
return config.get(BASELINE_KEY)
54-
.map(::createBaselineFacade)
55-
.orElse(null)
56-
}
57-
5827
private fun reportIssue(issue: Finding) {
5928
if (issue.id in excludedDuplicates) {
6029
return

0 commit comments

Comments
 (0)