Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

Refactor Gradle extensions to use lazy configuration #36

Merged
merged 6 commits into from
Jan 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class DetektAnalysisExtension(
private val log: MessageCollector,
private val spec: ProcessingSpec,
private val rootPath: Path,
private val excludes: Set<String>
private val excludes: Collection<String>
) : AnalysisHandlerExtension {

override fun analysisCompleted(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ class DetektCommandLineProcessor : CommandLineProcessor {

override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
when (option.optionName) {
Options.baseline -> configuration.put(Keys.BASELINE, value)
Options.config -> configuration.put(Keys.CONFIG, value)
Options.baseline -> configuration.put(Keys.BASELINE, Paths.get(value))
Options.config -> configuration.put(Keys.CONFIG, value.split(",;").map { Paths.get(it) })
Options.debug -> configuration.put(Keys.DEBUG, value.toBoolean())
Options.isEnabled -> configuration.put(Keys.IS_ENABLED, value.toBoolean())
Options.useDefaultConfig -> configuration.put(Keys.USE_DEFAULT_CONFIG, value)
Options.useDefaultConfig -> configuration.put(Keys.USE_DEFAULT_CONFIG, value.toBoolean())
BraisGabin marked this conversation as resolved.
Show resolved Hide resolved
Options.rootPath -> configuration.put(Keys.ROOT_PATH, Paths.get(value))
Options.excludes -> configuration.put(Keys.EXCLUDES, value.decodeToGlobSet())
Options.report -> configuration.put(Keys.REPORTS, value.substringBefore(':'), Paths.get(value.substringAfter(':')))
Expand All @@ -89,12 +89,12 @@ class DetektCommandLineProcessor : CommandLineProcessor {
}
}

private fun String.decodeToGlobSet(): Set<String> {
private fun String.decodeToGlobSet(): List<String> {
val b = Base64.getDecoder().decode(this)
val bi = ByteArrayInputStream(b)

return ObjectInputStream(bi).use { inputStream ->
val globs = mutableSetOf<String>()
val globs = mutableListOf<String>()

repeat(inputStream.readInt()) {
globs.add(inputStream.readUTF())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DetektComponentRegistrar : ComponentRegistrar {
messageCollector,
configuration.toSpec(messageCollector),
configuration.get(Keys.ROOT_PATH, Paths.get(System.getProperty("user.dir"))),
configuration.get(Keys.EXCLUDES, emptySet())
configuration.getList(Keys.EXCLUDES)
)
)
}
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/io/github/detekt/compiler/plugin/Keys.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ object Keys {

val DEBUG = CompilerConfigurationKey.create<Boolean>(Options.debug)
val IS_ENABLED = CompilerConfigurationKey.create<Boolean>(Options.isEnabled)
val CONFIG = CompilerConfigurationKey.create<String>(Options.config)
val BASELINE = CompilerConfigurationKey.create<String>(Options.baseline)
val USE_DEFAULT_CONFIG = CompilerConfigurationKey.create<String>(Options.useDefaultConfig)
val CONFIG = CompilerConfigurationKey.create<List<Path>>(Options.config)
val BASELINE = CompilerConfigurationKey.create<Path>(Options.baseline)
val USE_DEFAULT_CONFIG = CompilerConfigurationKey.create<Boolean>(Options.useDefaultConfig)
val ROOT_PATH = CompilerConfigurationKey.create<Path>(Options.rootPath)
val EXCLUDES = CompilerConfigurationKey.create<Set<String>>(Options.excludes)
val EXCLUDES = CompilerConfigurationKey.create<List<String>>(Options.excludes)
val REPORTS = CompilerConfigurationKey.create<Map<String, Path>>(Options.report)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,22 @@ import io.github.detekt.compiler.plugin.Keys
import io.github.detekt.tooling.api.spec.ProcessingSpec
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.CompilerConfiguration
import java.nio.file.Paths

internal fun CompilerConfiguration.toSpec(log: MessageCollector) = ProcessingSpec.invoke {
config {
configPaths = get(Keys.CONFIG)?.split(",;")?.map { Paths.get(it) } ?: emptyList()
useDefaultConfig = get(Keys.USE_DEFAULT_CONFIG)?.toBoolean() ?: false
configPaths = getList(Keys.CONFIG)
useDefaultConfig = get(Keys.USE_DEFAULT_CONFIG, false)
}
baseline {
path = get(Keys.BASELINE)?.let { Paths.get(it) }
path = get(Keys.BASELINE)
}
logging {
debug = get(Keys.DEBUG) ?: false
debug = get(Keys.DEBUG, false)
outputChannel = AppendableAdapter { log.info(it) }
errorChannel = AppendableAdapter { log.error(it) }
}
reports {
get(Keys.REPORTS)?.forEach {
getMap(Keys.REPORTS).forEach {
report { Pair(it.key, it.value) }
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package io.github.detekt.gradle

import io.github.detekt.compiler.plugin.Options
import io.github.detekt.gradle.extensions.ProjectDetektExtension
import io.github.detekt.gradle.extensions.KotlinCompileTaskDetektExtension
import io.github.detekt.gradle.extensions.ProjectDetektExtension
import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFile
import org.gradle.api.plugins.ReportingBasePlugin
import org.gradle.api.provider.Provider
import org.gradle.api.reporting.ReportingExtension
Expand All @@ -25,66 +24,76 @@ class DetektKotlinCompilerPlugin : KotlinCompilerPluginSupportPlugin {

override fun apply(target: Project) {
target.pluginManager.apply(ReportingBasePlugin::class.java)
val extension = target.extensions.create(DETEKT_NAME, ProjectDetektExtension::class.java)
extension.reportsDir = target.extensions.getByType(ReportingExtension::class.java).file(DETEKT_NAME)
extension.excludes.add("**/${target.relativePath(target.buildDir)}/**")

val defaultConfigFile = getDefaultConfigFile(target)
val projectExtension = target.extensions.create(DETEKT_NAME, ProjectDetektExtension::class.java).apply {
reportsDir.convention(
target.extensions.getByType(ReportingExtension::class.java).baseDirectory.dir(DETEKT_NAME)
)
excludes.add("**/${target.relativePath(target.buildDir)}/**")

if (defaultConfigFile.exists()) {
extension.config = target.files(defaultConfigFile)
isEnabled.convention(true)
debug.convention(false)
buildUponDefaultConfig.convention(true)
config.from(target.rootProject.layout.projectDirectory.dir(CONFIG_DIR_NAME).file(CONFIG_FILE))
}

target.configurations.create(CONFIGURATION_DETEKT_PLUGINS) { configuration ->
configuration.isVisible = false
configuration.isTransitive = true
configuration.description = "The $CONFIGURATION_DETEKT_PLUGINS libraries to be used for this project."
target.configurations.create(CONFIGURATION_DETEKT_PLUGINS).apply {
isVisible = false
isTransitive = true
description = "The $CONFIGURATION_DETEKT_PLUGINS libraries to be used for this project."
}

target.tasks.withType(KotlinCompile::class.java).configureEach { task ->
task.extensions.create(DETEKT_NAME, KotlinCompileTaskDetektExtension::class.java, target)
task.extensions.create(DETEKT_NAME, KotlinCompileTaskDetektExtension::class.java, target).apply {
enabled.convention(projectExtension.isEnabled)
baseline.convention(projectExtension.baseline)
debug.convention(projectExtension.debug)
buildUponDefaultConfig.convention(projectExtension.buildUponDefaultConfig)
config.from(projectExtension.config)
excludes.convention(projectExtension.excludes)
}
}
}

override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> {
val project = kotlinCompilation.target.project
val providers = project.providers

val extension = project.extensions.getByType(ProjectDetektExtension::class.java)
val taskExtension = kotlinCompilation.compileKotlinTask.extensions.getByType(KotlinCompileTaskDetektExtension::class.java)

val reportsDir: Provider<RegularFile> = project.layout.file(providers.provider { extension.reportsDir })
val projectExtension = project.extensions.getByType(ProjectDetektExtension::class.java)
val taskExtension =
kotlinCompilation.compileKotlinTask.extensions.getByType(KotlinCompileTaskDetektExtension::class.java)

project.configurations.getByName("kotlinCompilerPluginClasspath").apply {
extendsFrom(project.configurations.getAt(CONFIGURATION_DETEKT_PLUGINS))
}

val options = project.objects.listProperty(SubpluginOption::class.java).apply {
add(SubpluginOption(Options.debug, extension.debug.toString()))
add(SubpluginOption(Options.configDigest, extension.config.toDigest()))
add(SubpluginOption(Options.isEnabled, extension.isEnabled.toString()))
add(SubpluginOption(Options.useDefaultConfig, extension.buildUponDefaultConfig.toString()))
add(SubpluginOption(Options.debug, taskExtension.debug.get().toString()))
add(SubpluginOption(Options.configDigest, taskExtension.config.toDigest()))
add(SubpluginOption(Options.isEnabled, taskExtension.enabled.get().toString()))
add(SubpluginOption(Options.useDefaultConfig, taskExtension.buildUponDefaultConfig.get().toString()))
add(SubpluginOption(Options.rootPath, project.rootDir.toString()))
add(SubpluginOption(Options.excludes, extension.excludes.get().encodeToBase64()))
add(SubpluginOption(Options.excludes, taskExtension.excludes.get().encodeToBase64()))

taskExtension.reports.all { report ->
report.enabled.convention(true)
report.destination.convention(
project.layout.projectDirectory.file(providers.provider {
val reportFileName = "${kotlinCompilation.name}.${report.name}"
File(reportsDir.get().asFile, reportFileName).absolutePath
})
projectExtension.reportsDir.file("${kotlinCompilation.name}.${report.name}")
)

if (report.enabled.get()) {
add(SubpluginOption(Options.report, "${report.name}:${report.destination.asFile.get().absolutePath}"))
add(
SubpluginOption(
Options.report,
"${report.name}:${report.destination.asFile.get().absolutePath}"
)
)
}
}
}

extension.baseline?.let { options.add(SubpluginOption(Options.baseline, it.toString())) }
if (extension.config.any()) {
options.add(SubpluginOption(Options.config, extension.config.joinToString(",")))
taskExtension.baseline.getOrNull()?.let { options.add(SubpluginOption(Options.baseline, it.toString())) }
if (taskExtension.config.any()) {
options.add(SubpluginOption(Options.config, taskExtension.config.joinToString(",")))
}

return options
Expand All @@ -97,9 +106,6 @@ class DetektKotlinCompilerPlugin : KotlinCompilerPluginSupportPlugin {

override fun isApplicable(kotlinCompilation: KotlinCompilation<*>): Boolean =
kotlinCompilation.platformType in setOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm)

private fun getDefaultConfigFile(target: Project) =
target.file("${target.rootProject.layout.projectDirectory.dir(CONFIG_DIR_NAME)}/$CONFIG_FILE")
}

internal fun ConfigurableFileCollection.toDigest(): String {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package io.github.detekt.gradle.extensions

import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty

open class KotlinCompileTaskDetektExtension(project: Project) {
val reports = project.container(DetektReport::class.java)
Expand All @@ -16,4 +21,14 @@ open class KotlinCompileTaskDetektExtension(project: Project) {
fun getHtml() = reports.getByName("html")
fun getTxt() = reports.getByName("txt")
fun getSarif() = reports.getByName("sarif")

private val objects: ObjectFactory = project.objects

val enabled: Property<Boolean> = objects.property(Boolean::class.java)
val baseline: RegularFileProperty = objects.fileProperty()
val debug: Property<Boolean> = objects.property(Boolean::class.java)
val buildUponDefaultConfig: Property<Boolean> = objects.property(Boolean::class.java)
val config: ConfigurableFileCollection = objects.fileCollection()
val excludes: SetProperty<String> = objects.setProperty(String::class.java)

}
Original file line number Diff line number Diff line change
@@ -1,31 +1,22 @@
package io.github.detekt.gradle.extensions

import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.quality.CodeQualityExtension
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import java.io.File
import javax.inject.Inject

open class ProjectDetektExtension constructor(@Inject val objects: ObjectFactory) : CodeQualityExtension() {
open class ProjectDetektExtension @Inject constructor(objects: ObjectFactory) {

var isEnabled: Boolean = true
var baseline: File? = null
var debug: Boolean = false
var parallel: Boolean = false
var failFast: Boolean = false
var buildUponDefaultConfig: Boolean = true
var disableDefaultRuleSets: Boolean = false
var autoCorrect: Boolean = false
val isEnabled: Property<Boolean> = objects.property(Boolean::class.java)
val baseline: RegularFileProperty = objects.fileProperty()
val debug: Property<Boolean> = objects.property(Boolean::class.java)
val buildUponDefaultConfig: Property<Boolean> = objects.property(Boolean::class.java)

var config: ConfigurableFileCollection = objects.fileCollection()
val config: ConfigurableFileCollection = objects.fileCollection()
val excludes: SetProperty<String> = objects.setProperty(String::class.java)
val reportsDir: DirectoryProperty = objects.directoryProperty()

var ignoreFailures: Boolean
@JvmName("ignoreFailures_")
get() = isIgnoreFailures
@JvmName("ignoreFailures_")
set(value) {
isIgnoreFailures = value
}
}