Skip to content

Commit

Permalink
cli handles the filters
Browse files Browse the repository at this point in the history
  • Loading branch information
BraisGabin committed Mar 27, 2024
1 parent dbfabdc commit 218223a
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 69 deletions.
33 changes: 30 additions & 3 deletions detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/Spec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import io.github.detekt.tooling.api.spec.ProcessingSpec
import io.github.detekt.tooling.api.spec.RulesSpec
import io.gitlab.arturbosch.detekt.api.Rule
import io.gitlab.arturbosch.detekt.api.RuleSet
import io.gitlab.arturbosch.detekt.api.internal.PathFilters
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.absolute
import kotlin.io.path.extension
import kotlin.io.path.walk

@Suppress("LongMethod")
internal fun CliArgs.createSpec(output: Appendable, error: Appendable): ProcessingSpec {
val args = this
return ProcessingSpec {
Expand All @@ -16,9 +23,20 @@ internal fun CliArgs.createSpec(output: Appendable, error: Appendable): Processi

project {
basePath = args.basePath
inputPaths = args.inputPaths
excludes = args.excludes?.let(::asPatterns).orEmpty()
includes = args.includes?.let(::asPatterns).orEmpty()
val pathFilters = PathFilters.of(
args.excludes?.let(::asPatterns).orEmpty(),
args.includes?.let(::asPatterns).orEmpty(),
)
inputPaths = args.inputPaths.walk()
.map { it.absolute().normalize() }
.filter { pathFilters?.isIgnored(it) != false }
.filter { path ->
path.isKotlinFile()
.also {
if (!it && args.debug) output.appendLine("Ignoring a file detekt cannot handle: $path")
}
}
.toSet()
}

rules {
Expand Down Expand Up @@ -66,6 +84,15 @@ internal fun CliArgs.createSpec(output: Appendable, error: Appendable): Processi
}
}

@OptIn(ExperimentalPathApi::class)
private fun Iterable<Path>.walk(): Sequence<Path> {
return asSequence().flatMap { it.walk() }
}

private fun Path.isKotlinFile() = extension in KT_ENDINGS

private val KT_ENDINGS = setOf("kt", "kts")

private fun asPatterns(rawValue: String): List<String> = rawValue.trim()
.splitToSequence(",", ";")
.filter { it.isNotBlank() }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package io.gitlab.arturbosch.detekt.cli

import io.github.detekt.test.utils.NullPrintStream
import io.github.detekt.test.utils.resourceAsPath
import io.github.detekt.tooling.api.spec.RulesSpec.FailurePolicy.FailOnSeverity
import io.github.detekt.tooling.api.spec.RulesSpec.FailurePolicy.NeverFail
import io.gitlab.arturbosch.detekt.api.Severity
import io.gitlab.arturbosch.detekt.api.internal.PathFilters
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode
import org.assertj.core.api.Assertions.assertThatExceptionOfType
Expand All @@ -15,31 +13,30 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.EnumSource
import org.junit.jupiter.params.provider.ValueSource
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.absolute

internal class CliArgsSpec {

@Nested
inner class `Parsing the input path` {
private val projectPath = resourceAsPath("/").parent.parent.parent.parent
private val pathBuildGradle = Path("build.gradle.kts").absolute()
private val pathCliArgs = Path("src/main/kotlin/io/gitlab/arturbosch/detekt/cli/CliArgs.kt").absolute()
private val pathCliArgsSpec = Path("src/test/kotlin/io/gitlab/arturbosch/detekt/cli/CliArgsSpec.kt").absolute()
private val pathAnalyzer =
Path("../detekt-core/src/test/kotlin/io/gitlab/arturbosch/detekt/core/AnalyzerSpec.kt").absolute()
.normalize()

@Test
fun `the current working directory is used if parameter is not set`() {
val spec = parseArguments(emptyArray()).toSpec()
assertThat(spec.projectSpec.inputPaths).containsExactly(Path("").absolute())
}

@Test
fun `a single value is converted to a path`() {
val spec = parseArguments(arrayOf("--input", "$projectPath")).toSpec()
assertThat(spec.projectSpec.inputPaths).containsExactly(projectPath)
}
val workingDir = Path("").toAbsolutePath()

@Test
fun `a single value is converted to a path absolute`() {
val spec = parseArguments(arrayOf("--input", "${projectPath.absolute()}")).toSpec()
assertThat(spec.projectSpec.inputPaths).containsExactly(projectPath.absolute())
assertThat(spec.projectSpec.inputPaths).allSatisfy { it.toAbsolutePath().startsWith(workingDir) }
assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgsSpec)
}

@ParameterizedTest
Expand All @@ -52,11 +49,11 @@ internal class CliArgsSpec {
)
fun `when the input is defined it is passed to the spec`(param: String) {
val spec = parseArguments(arrayOf("--input", param)).toSpec()
assertThat(spec.projectSpec.inputPaths).containsExactly(
Path("src/main"),
Path("../detekt-core/src/test"),
Path("build.gradle.kts"),
)

assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathCliArgsSpec)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}

@Test
Expand All @@ -67,6 +64,110 @@ internal class CliArgsSpec {
.isThrownBy { parseArguments(params) }
.withMessage("Input path does not exist: 'nonExistent '")
}

@Nested
inner class FilterInput {
private val input = arrayOf("--input", "src/main/../main/,../detekt-core/src/test,build.gradle.kts")
private val pathMain = Path("src/main/kotlin/io/gitlab/arturbosch/detekt/cli/Main.kt").absolute()

@Test
fun `no filters`() {
val spec = parseArguments(input).toSpec()

assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}

@Test
fun `excludes in path`() {
val spec = parseArguments(input + arrayOf("--excludes", "**/test/**")).toSpec()

assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathMain)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathAnalyzer)
}

@Test
fun `includes in path`() {
val spec = parseArguments(input + arrayOf("--includes", "**/test/**")).toSpec()

assertThat(spec.projectSpec.inputPaths).doesNotContain(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}

@Test
fun `excludes and includes in path`() {
val spec = parseArguments(input + arrayOf("--excludes", "**/test/**", "--includes", "**/test/**"))
.toSpec()

assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).contains(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}

@Test
fun `excludes in path normalized`() {
val spec = parseArguments(input + arrayOf("--excludes", "**/src/main/kotlin/**")).toSpec()

assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}

@Test
fun `excludes main but includes one file`() {
val spec = parseArguments(input + arrayOf("--excludes", "**/main/**", "--includes", "**/CliArgs.kt"))
.toSpec()

assertThat(spec.projectSpec.inputPaths).contains(pathBuildGradle)
assertThat(spec.projectSpec.inputPaths).contains(pathCliArgs)
assertThat(spec.projectSpec.inputPaths).doesNotContain(pathMain)
assertThat(spec.projectSpec.inputPaths).contains(pathAnalyzer)
}

@Test
fun `parse excludes correctly`() {
val paths: List<Collection<Path>> = listOf(
"**/main/**,**/detekt-core/**,**/build.gradle.kts",
"**/main/**;**/detekt-core/**;**/build.gradle.kts",
"**/main/** ,**/detekt-core/**, **/build.gradle.kts",
"**/main/** ;**/detekt-core/**; **/build.gradle.kts",
"**/main/**,**/detekt-core/**;**/build.gradle.kts",
"**/main/** ,**/detekt-core/**; **/build.gradle.kts",
" ,,**/main/**,**/detekt-core/**,**/build.gradle.kts",
).map {
val spec = parseArguments(input + arrayOf("--excludes", it)).toSpec()
spec.projectSpec.inputPaths
}

assertThat(paths.distinct()).hasSize(1)
}

@Test
fun `parse includes correctly`() {
val paths: List<Collection<Path>> = listOf(
"**/main/**,**/detekt-core/**,**/build.gradle.kts",
"**/main/**;**/detekt-core/**;**/build.gradle.kts",
"**/main/** ,**/detekt-core/**, **/build.gradle.kts",
"**/main/** ;**/detekt-core/**; **/build.gradle.kts",
"**/main/**,**/detekt-core/**;**/build.gradle.kts",
"**/main/** ,**/detekt-core/**; **/build.gradle.kts",
" ,,**/main/**,**/detekt-core/**,**/build.gradle.kts",
).map {
val spec = parseArguments(input + arrayOf("--includes", it)).toSpec()
spec.projectSpec.inputPaths
}

assertThat(paths.distinct()).hasSize(1)
}
}
}

@Nested
Expand Down Expand Up @@ -129,47 +230,6 @@ internal class CliArgsSpec {
assertThat(spec.rulesSpec.activateAllRules).isTrue()
}

@Test
fun `should load single filter`() {
val filters = CliArgs { excludes = "**/one/**" }.toSpecFilters()
assertThat(filters?.isIgnored(Path("/one/path"))).isTrue()
assertThat(filters?.isIgnored(Path("/two/path"))).isFalse()
}

@ParameterizedTest
@ValueSource(
strings = [
"**/one/**,**/two/**,**/three",
"**/one/**;**/two/**;**/three",
"**/one/** ,**/two/**, **/three",
"**/one/** ;**/two/**; **/three",
"**/one/**,**/two/**;**/three",
"**/one/** ,**/two/**; **/three",
" ,,**/one/**,**/two/**,**/three",
]
)
fun parseExcludes(param: String) {
val spec = parseArguments(arrayOf("--excludes", param)).toSpec()
assertThat(spec.projectSpec.excludes).containsExactly("**/one/**", "**/two/**", "**/three")
}

@ParameterizedTest
@ValueSource(
strings = [
"**/one/**,**/two/**,**/three",
"**/one/**;**/two/**;**/three",
"**/one/** ,**/two/**, **/three",
"**/one/** ;**/two/**; **/three",
"**/one/**,**/two/**;**/three",
"**/one/** ,**/two/**; **/three",
" ,,**/one/**,**/two/**,**/three",
]
)
fun parseIncludes(param: String) {
val spec = parseArguments(arrayOf("--includes", param)).toSpec()
assertThat(spec.projectSpec.includes).containsExactly("**/one/**", "**/two/**", "**/three")
}

@Nested
inner class `type resolution parameters are accepted` {

Expand Down Expand Up @@ -248,8 +308,3 @@ internal class CliArgsSpec {
.withMessage("Value passed to --jdk-home must be a directory.")
}
}

private fun CliArgs.toSpecFilters(): PathFilters? {
val spec = this.createSpec(NullPrintStream(), NullPrintStream()).projectSpec
return PathFilters.of(spec.includes.toList(), spec.excludes.toList())
}

0 comments on commit 218223a

Please sign in to comment.