Skip to content

Commit

Permalink
Register Detekt task for each source set (detekt#6973)
Browse files Browse the repository at this point in the history
* Create detekt task for every Kotlin source set

* Update tests

* create baseline task

* Add tests for source set analysis tasks
  • Loading branch information
3flex committed Feb 22, 2024
1 parent dd4eb91 commit 387ca60
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 2 deletions.
@@ -0,0 +1,190 @@
package dev.detekt.gradle.plugin

import io.gitlab.arturbosch.detekt.testkit.DslGradleRunner
import io.gitlab.arturbosch.detekt.testkit.ProjectLayout
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.condition.EnabledForJreRange
import org.junit.jupiter.api.condition.JRE
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource

class DetektBasePluginSpec {
@Test
fun `generates source set tasks for JVM project`() {
val gradleRunner = DslGradleRunner(
projectLayout = ProjectLayout(
numberOfSourceFilesInRootPerSourceDir = 1,
srcDirs = listOf(
"src/main/kotlin",
"src/test/kotlin",
),
),
buildFileName = "build.gradle.kts",
mainBuildFileContent = """
plugins {
id("io.gitlab.arturbosch.detekt")
kotlin("jvm")
}
repositories {
mavenLocal()
mavenCentral()
}
""".trimIndent(),
dryRun = true,
).also {
it.setupProject()
}

gradleRunner.checkTask("main")
gradleRunner.checkTask("test")
}

@Test
@EnabledForJreRange(min = JRE.JAVA_17, disabledReason = "Android Gradle Plugin 8.0+ requires JDK 17 or newer")
fun `generates source set tasks for Android project`() {
val gradleRunner = DslGradleRunner(
projectLayout = ProjectLayout(
numberOfSourceFilesInRootPerSourceDir = 1,
srcDirs = listOf(
"src/main/kotlin",
"src/debug/kotlin",
"src/test/kotlin",
"src/androidTest/kotlin",
),
),
buildFileName = "build.gradle.kts",
mainBuildFileContent = """
plugins {
id("io.gitlab.arturbosch.detekt")
id("com.android.library")
kotlin("android")
}
repositories {
mavenLocal()
mavenCentral()
google()
}
android {
compileSdk = 30
namespace = "dev.detekt.gradle.plugin.app"
}
""".trimIndent(),
dryRun = true,
).also {
it.setupProject()
}

gradleRunner.checkTask("main")
gradleRunner.checkTask("debug")
gradleRunner.checkTask("test")
gradleRunner.checkTask("androidTest")
}

@Nested
@EnabledForJreRange(min = JRE.JAVA_17, disabledReason = "Android Gradle Plugin 8.0+ requires JDK 17 or newer")
inner class `generates source set tasks for KMP project` {
val gradleRunner = DslGradleRunner(
projectLayout = ProjectLayout(
numberOfSourceFilesInRootPerSourceDir = 1,
srcDirs = listOf(
"src/commonMain/kotlin",
"src/commonTest/kotlin",
"src/androidMain/kotlin",
"src/androidUnitTest/kotlin",
"src/androidInstrumentedTest/kotlin",
"src/jvmMain/kotlin",
"src/jvmTest/kotlin",
"src/jsMain/kotlin",
"src/jsTest/kotlin",
"src/iosMain/kotlin",
"src/iosTest/kotlin",
"src/appleMain/kotlin",
"src/appleTest/kotlin",
"src/nativeMain/kotlin",
"src/nativeTest/kotlin",
),
),
buildFileName = "build.gradle.kts",
mainBuildFileContent = """
plugins {
id("io.gitlab.arturbosch.detekt")
kotlin("multiplatform")
id("com.android.library")
}
repositories {
mavenLocal()
mavenCentral()
google()
}
kotlin {
androidTarget()
iosArm64()
iosSimulatorArm64()
jvm()
js {
browser()
nodejs()
}
}
android {
compileSdk = 30
namespace = "dev.detekt.gradle.plugin.app"
}
""".trimIndent(),
dryRun = true,
).also {
it.setupProject()
}

@ParameterizedTest
@ValueSource(strings = ["commonMain", "commonTest"])
fun `generates source set tasks for common code`(sourceSetTaskName: String) {
gradleRunner.checkTask(sourceSetTaskName)
}

@ParameterizedTest
@ValueSource(strings = ["androidMain", "androidUnitTest", "androidInstrumentedTest"])
fun `generates source set tasks for Android`(sourceSetTaskName: String) {
gradleRunner.checkTask(sourceSetTaskName)
}

@ParameterizedTest
@ValueSource(strings = ["jvmMain", "jvmTest"])
fun `generates source set tasks for JVM`(sourceSetTaskName: String) {
gradleRunner.checkTask(sourceSetTaskName)
}

@ParameterizedTest
@ValueSource(strings = ["jsMain", "jsTest"])
fun `generates source set tasks for JS`(sourceSetTaskName: String) {
gradleRunner.checkTask(sourceSetTaskName)
}

@ParameterizedTest
@ValueSource(strings = ["iosMain", "iosTest", "appleMain", "appleTest", "nativeMain", "nativeTest"])
fun `generates source set tasks for iOS native`(sourceSetTaskName: String) {
gradleRunner.checkTask(sourceSetTaskName)
}
}

private fun DslGradleRunner.checkTask(sourceSetTaskName: String) {
runTasksAndCheckResult(":detekt${sourceSetTaskName}SourceSet") { buildResult ->
assertThat(buildResult.output)
.containsPattern("""--input \S*[/\\]src[/\\]$sourceSetTaskName[/\\]kotlin""")
val xmlReportFile = projectFile("build/reports/detekt/$sourceSetTaskName.xml")
val sarifReportFile = projectFile("build/reports/detekt/$sourceSetTaskName.sarif")
val txtReportFile = projectFile("build/reports/detekt/$sourceSetTaskName.txt")
assertThat(buildResult.output).contains("--report xml:$xmlReportFile")
assertThat(buildResult.output).contains("--report sarif:$sarifReportFile")
assertThat(buildResult.output).contains("--report txt:$txtReportFile")
}
}
}
Expand Up @@ -140,15 +140,17 @@ class DetektAndroidSpec {
@DisplayName("task :app:detektMain")
fun appDetektMain() {
gradleRunner.runTasksAndExpectFailure(":app:detektMain") { result ->
assertThat(result.output).containsIgnoringCase("Task 'detektMain' not found in project")
assertThat(result.output)
.contains("Cannot locate tasks that match ':app:detektMain' as task 'detektMain' is ambiguous")
}
}

@Test
@DisplayName("task :app:detektTest")
fun appDetektTest() {
gradleRunner.runTasksAndExpectFailure(":app:detektTest") { result ->
assertThat(result.output).containsIgnoringCase("Task 'detektTest' not found in project")
assertThat(result.output)
.contains("Cannot locate tasks that match ':app:detektTest' as task 'detektTest' is ambiguous")
}
}
}
Expand Down
@@ -1,12 +1,21 @@
package dev.detekt.gradle.plugin

import io.gitlab.arturbosch.detekt.DetektPlugin
import io.gitlab.arturbosch.detekt.extensions.DetektExtension
import io.gitlab.arturbosch.detekt.extensions.FailOnSeverity
import io.gitlab.arturbosch.detekt.extensions.loadDetektVersion
import io.gitlab.arturbosch.detekt.internal.addVariantName
import io.gitlab.arturbosch.detekt.internal.existingVariantOrBaseFile
import io.gitlab.arturbosch.detekt.internal.registerCreateBaselineTask
import io.gitlab.arturbosch.detekt.internal.registerDetektTask
import io.gitlab.arturbosch.detekt.internal.setReportOutputConventions
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.ReportingBasePlugin
import org.gradle.api.reporting.ReportingExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetContainer

class DetektBasePlugin : Plugin<Project> {
override fun apply(project: Project) {
Expand Down Expand Up @@ -51,6 +60,40 @@ class DetektBasePlugin : Plugin<Project> {
configuration.isCanBeResolved = true
configuration.isCanBeConsumed = false
}

project.registerSourceSetTasks(extension)
}

private fun Project.registerSourceSetTasks(extension: DetektExtension) {
project.plugins.withType(KotlinBasePlugin::class.java) {
project.extensions.getByType(KotlinSourceSetContainer::class.java)
.sourceSets
.withType(KotlinSourceSet::class.java) { sourceSet ->
val taskName = "${DetektPlugin.DETEKT_TASK_NAME}${sourceSet.name.capitalize()}SourceSet"
project.registerDetektTask(taskName, extension) {
source = sourceSet.kotlin
// If a baseline file is configured as input file, it must exist to be configured, otherwise the task fails.
// We try to find the configured baseline or alternatively a specific variant matching this task.
extension.baseline.asFile.orNull?.existingVariantOrBaseFile("${sourceSet.name}SourceSet")
?.let { file ->
baseline.convention(project.layout.file(project.provider { file }))
}
setReportOutputConventions(reports, extension, sourceSet.name)
description = "Run detekt analysis for ${sourceSet.name} source set"
}

val baseLineTaskName = "${DetektPlugin.BASELINE_TASK_NAME}${sourceSet.name.capitalize()}SourceSet"
project.registerCreateBaselineTask(baseLineTaskName, extension) {
source = sourceSet.kotlin

val variantBaselineFile =
extension.baseline.asFile.orNull?.addVariantName("${sourceSet.name}SourceSet")
baseline.convention(project.layout.file(project.provider { variantBaselineFile }))

description = "Creates detekt baseline for ${sourceSet.name} source set"
}
}
}
}

internal companion object {
Expand Down

0 comments on commit 387ca60

Please sign in to comment.