Make rulesets configurable

This commit is contained in:
ArtiSmarti
2016-10-19 15:39:13 +02:00
parent 3dbb76e52f
commit 405430a763
13 changed files with 152 additions and 13 deletions

View File

@@ -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"
}

View File

@@ -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())
}
}

View File

@@ -6,5 +6,4 @@ import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
* @author artur
*/
open class KastVisitor : KtTreeVisitorVoid() {
}

View File

@@ -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) {

View File

@@ -4,6 +4,5 @@ package io.gitlab.arturbosch.detekt.api
* @author Artur Bosch
*/
interface RuleSetProvider {
fun instance(): RuleSet
fun instance(config: Config): RuleSet
}

View File

@@ -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
}
}

View File

@@ -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") { "" }
}
}
}
})

View 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

View File

@@ -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()

View File

@@ -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()
}

View File

@@ -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())
}
}

View File

@@ -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(),

View File

@@ -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()