mirror of
https://github.com/jlengrand/detekt.git
synced 2026-03-10 08:11:23 +00:00
Make rulesets configurable
This commit is contained in:
@@ -1,22 +1,39 @@
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.0.4'
|
||||
ext.spek_version = '1.1.18'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M2'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'org.junit.platform.gradle.plugin'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "http://dl.bintray.com/jetbrains/spek"
|
||||
}
|
||||
}
|
||||
|
||||
junitPlatform {
|
||||
engines {
|
||||
include 'spek'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
compile "org.jetbrains.kotlin:kotlin-compiler:$kotlin_version"
|
||||
compile group: 'org.yaml', name: 'snakeyaml', version: '1.17'
|
||||
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
testCompile "org.jetbrains.spek:spek-api:$spek_version"
|
||||
testRuntime 'org.junit.platform:junit-platform-launcher:1.0.0-M2'
|
||||
testRuntime "org.jetbrains.spek:spek-junit-platform-engine:$spek_version"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,41 @@
|
||||
package io.gitlab.arturbosch.detekt.api
|
||||
|
||||
import org.yaml.snakeyaml.Yaml
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
/**
|
||||
* @author Artur Bosch
|
||||
*/
|
||||
class Config(val properties: Map<String, Any>)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class Config private constructor(val properties: Map<String, Any>) {
|
||||
|
||||
fun subConfig(key: String): Config {
|
||||
val subProperties = properties.getOrElse(key) { mapOf<String, Any>() }
|
||||
return Config(subProperties as Map<String, Any>)
|
||||
}
|
||||
|
||||
fun <T : Any> valueOrDefault(key: String, default: () -> T): T {
|
||||
return properties.getOrElse(key) { default() } as T
|
||||
}
|
||||
|
||||
internal class InvalidConfigurationError(msg: String = "Provided configuration file is invalid:" +
|
||||
" Structure must be of type Map<String,Any>!") : RuntimeException(msg)
|
||||
|
||||
companion object {
|
||||
fun load(path: Path): Config {
|
||||
require(Files.exists(path) && path.toString().endsWith("yml"))
|
||||
return Files.newBufferedReader(path).use {
|
||||
val map = Yaml().loadAll(it).iterator().next()
|
||||
if (map is Map<*, *>) {
|
||||
Config(map as Map<String, Any>)
|
||||
} else {
|
||||
throw InvalidConfigurationError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val EMPTY: Config = Config(mapOf())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,5 +6,4 @@ import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
|
||||
* @author artur
|
||||
*/
|
||||
open class KastVisitor : KtTreeVisitorVoid() {
|
||||
|
||||
}
|
||||
@@ -20,16 +20,20 @@ abstract class Rule(val id: String, val severity: Severity = Rule.Severity.Minor
|
||||
}
|
||||
|
||||
open fun visit(root: ASTNode) {
|
||||
clearFindings()
|
||||
preVisit(root)
|
||||
root.visit(this)
|
||||
postVisit(root)
|
||||
}
|
||||
|
||||
internal fun clearFindings() {
|
||||
_findings = mutableListOf()
|
||||
}
|
||||
|
||||
protected open fun postVisit(root: ASTNode) {
|
||||
}
|
||||
|
||||
protected open fun preVisit(root: ASTNode) {
|
||||
_findings = mutableListOf()
|
||||
}
|
||||
|
||||
protected fun addFindings(vararg finding: Finding) {
|
||||
|
||||
@@ -4,6 +4,5 @@ package io.gitlab.arturbosch.detekt.api
|
||||
* @author Artur Bosch
|
||||
*/
|
||||
interface RuleSetProvider {
|
||||
|
||||
fun instance(): RuleSet
|
||||
fun instance(config: Config): RuleSet
|
||||
}
|
||||
@@ -5,13 +5,14 @@ import com.intellij.lang.ASTNode
|
||||
/**
|
||||
* @author Artur Bosch
|
||||
*/
|
||||
abstract class TokenRule(id: String) : Rule(id) {
|
||||
abstract class TokenRule(id: String, severity: Severity = Rule.Severity.Minor) : Rule(id, severity) {
|
||||
|
||||
override fun visit(root: ASTNode) {
|
||||
clearFindings()
|
||||
preVisit(root)
|
||||
root.visitTokens { procedure(it) }
|
||||
postVisit(root)
|
||||
}
|
||||
|
||||
abstract fun procedure(node: ASTNode): Unit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package io.gitlab.arturbosch.detekt.api
|
||||
|
||||
import org.jetbrains.spek.api.Spek
|
||||
import org.jetbrains.spek.api.dsl.describe
|
||||
import org.jetbrains.spek.api.dsl.it
|
||||
import java.nio.file.Paths
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
/**
|
||||
* @author Artur Bosch
|
||||
*/
|
||||
class ConfigSpec : Spek({
|
||||
|
||||
describe("load yaml config") {
|
||||
val configPath = Paths.get(ConfigSpec::class.java.getResource("/detekt.yml").path)
|
||||
val config = Config.load(configPath)
|
||||
|
||||
it("should successfully load map of string to any with size two") {
|
||||
assertTrue { config.properties.size == 2 }
|
||||
}
|
||||
|
||||
it("should create a sub config") {
|
||||
try {
|
||||
val subConfig = config.subConfig("style")
|
||||
assertTrue { subConfig.valueOrDefault("WildcardImport", { mapOf<String, Any>() }).isNotEmpty() }
|
||||
assertTrue { subConfig.valueOrDefault("WildcardImport", { mapOf<String, Any>() })["active"].toString() == "true" }
|
||||
assertTrue { subConfig.valueOrDefault("WildcardImport", { mapOf<String, Any>() })["active"] as Boolean }
|
||||
assertTrue { subConfig.valueOrDefault("NotFound", { mapOf<String, Any>() }).isEmpty() }
|
||||
assertTrue { subConfig.valueOrDefault("NotFound", { "" }) == "" }
|
||||
} catch (ignored: Config.InvalidConfigurationError) {
|
||||
fail("Creating a sub config should work for test resources config!")
|
||||
}
|
||||
}
|
||||
|
||||
it("should create a sub sub config") {
|
||||
try {
|
||||
val subConfig = config.subConfig("style")
|
||||
val subSubConfig = subConfig.subConfig("WildcardImport")
|
||||
assertTrue { subSubConfig.properties["active"] as Boolean }
|
||||
assertTrue { subSubConfig.valueOrDefault("active") { false } }
|
||||
assertTrue { subSubConfig.valueOrDefault("NotFound") { true } }
|
||||
} catch (ignored: Config.InvalidConfigurationError) {
|
||||
fail("Creating a sub config should work for test resources config!")
|
||||
}
|
||||
}
|
||||
|
||||
it("tests wrong sub config conversion") {
|
||||
assertFailsWith<ClassCastException> {
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val ignored = config.valueOrDefault("style") { "" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
21
detekt-api/src/test/resources/detekt.yml
Normal file
21
detekt-api/src/test/resources/detekt.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
code-smell:
|
||||
LongMethod:
|
||||
active: true
|
||||
threshold: 20
|
||||
LongParameterList:
|
||||
active: false
|
||||
threshold: 5
|
||||
LargeClass:
|
||||
active: false
|
||||
threshold: 70
|
||||
InnerMap:
|
||||
Inner1:
|
||||
active: true
|
||||
Inner2:
|
||||
active: true
|
||||
|
||||
style:
|
||||
WildcardImport:
|
||||
active: true
|
||||
NoElseInWhenExpression:
|
||||
active: true
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.gitlab.arturbosch.detekt.cli.debug
|
||||
|
||||
import io.gitlab.arturbosch.detekt.api.Config
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSet
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSetProvider
|
||||
|
||||
@@ -7,7 +8,7 @@ import io.gitlab.arturbosch.detekt.api.RuleSetProvider
|
||||
* @author Artur Bosch
|
||||
*/
|
||||
object DebugRuleSetProvider : RuleSetProvider {
|
||||
override fun instance(): RuleSet {
|
||||
override fun instance(config: Config): RuleSet {
|
||||
return RuleSet("debug", listOf(
|
||||
ElementPrinter(),
|
||||
TokenPrinter()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.gitlab.arturbosch.detekt.core
|
||||
|
||||
import io.gitlab.arturbosch.detekt.api.Config
|
||||
import io.gitlab.arturbosch.detekt.api.Finding
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSetProvider
|
||||
import java.net.URLClassLoader
|
||||
@@ -11,6 +12,7 @@ import java.util.ServiceLoader
|
||||
* @author Artur Bosch
|
||||
*/
|
||||
class Detekt(project: Path,
|
||||
val config: Config = Config.EMPTY,
|
||||
val ruleSets: List<Path> = listOf(),
|
||||
pathFilters: List<PathFilter> = listOf(),
|
||||
parallelCompilation: Boolean = false) {
|
||||
@@ -26,7 +28,7 @@ class Detekt(project: Path,
|
||||
val ktFiles = compiler.compile()
|
||||
val providers = loadProviders()
|
||||
val futures = providers.map {
|
||||
task { it.instance().acceptAll(ktFiles) }
|
||||
task { it.instance(config).acceptAll(ktFiles) }
|
||||
}
|
||||
return awaitAll(futures).toMap()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.gitlab.arturbosch.detekt.core
|
||||
|
||||
import io.gitlab.arturbosch.detekt.api.Config
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSet
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSetProvider
|
||||
import java.nio.file.Path
|
||||
@@ -12,13 +13,13 @@ import java.nio.file.Paths
|
||||
val path: Path = Paths.get(KtTreeCompilerSpec::class.java.getResource("/cases").path)
|
||||
|
||||
class TestProvider : RuleSetProvider {
|
||||
override fun instance(): RuleSet {
|
||||
override fun instance(config: Config): RuleSet {
|
||||
return RuleSet("Test", listOf())
|
||||
}
|
||||
}
|
||||
|
||||
class TestProvider2 : RuleSetProvider {
|
||||
override fun instance(): RuleSet {
|
||||
override fun instance(config: Config): RuleSet {
|
||||
return RuleSet("Test", listOf())
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.gitlab.arturbosch.detekt.rules.providers
|
||||
|
||||
import io.gitlab.arturbosch.detekt.api.Config
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSet
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSetProvider
|
||||
import io.gitlab.arturbosch.detekt.rules.LargeClass
|
||||
@@ -10,7 +11,7 @@ import io.gitlab.arturbosch.detekt.rules.LongParameterList
|
||||
* @author Artur Bosch
|
||||
*/
|
||||
class CodeSmellProvider : RuleSetProvider {
|
||||
override fun instance(): RuleSet {
|
||||
override fun instance(config: Config): RuleSet {
|
||||
return RuleSet("code-smell", listOf(
|
||||
LongParameterList(),
|
||||
LongMethod(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.gitlab.arturbosch.detekt.rules.providers
|
||||
|
||||
import io.gitlab.arturbosch.detekt.api.Config
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSet
|
||||
import io.gitlab.arturbosch.detekt.api.RuleSetProvider
|
||||
import io.gitlab.arturbosch.detekt.rules.NoElseInWhenExpression
|
||||
@@ -9,7 +10,7 @@ import io.gitlab.arturbosch.detekt.rules.WildcardImport
|
||||
* @author Artur Bosch
|
||||
*/
|
||||
class StyleGuideProvider : RuleSetProvider {
|
||||
override fun instance(): RuleSet {
|
||||
override fun instance(config: Config): RuleSet {
|
||||
return RuleSet("style", listOf(
|
||||
WildcardImport(),
|
||||
NoElseInWhenExpression()
|
||||
|
||||
Reference in New Issue
Block a user