Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix regression generating configuration #4646

Merged
merged 5 commits into from Mar 29, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -114,7 +114,7 @@ class AnnotationExcluderSpec(private val env: KotlinCoreEnvironment) {
}

@Nested
inner class `Know where ends a package` {
inner class `Know where a package ends` {
val helloWorldAnnotationsKtFile = compileContentForTest(
"""
package com.Hello
Expand Down
Expand Up @@ -20,7 +20,7 @@ class CliRunner : DetektCli {

val specialRunner = when {
arguments.showVersion -> VersionPrinter(outputChannel)
arguments.generateConfig -> ConfigExporter(arguments, outputChannel, errorChannel)
arguments.generateConfig -> ConfigExporter(arguments, outputChannel)
arguments.printAst -> AstPrinter(arguments, outputChannel)
else -> null
}
Expand Down
Expand Up @@ -54,7 +54,7 @@ fun buildRunner(
val arguments = parseArguments(args)
return when {
arguments.showVersion -> VersionPrinter(outputPrinter)
arguments.generateConfig -> ConfigExporter(arguments, outputPrinter, errorPrinter)
arguments.generateConfig -> ConfigExporter(arguments, outputPrinter)
arguments.printAst -> AstPrinter(arguments, outputPrinter)
else -> Runner(arguments, outputPrinter, errorPrinter)
}
Expand Down
@@ -1,20 +1,25 @@
package io.gitlab.arturbosch.detekt.cli.runners

import io.github.detekt.tooling.api.DefaultConfigurationProvider
import io.github.detekt.tooling.api.spec.ProcessingSpec
import io.gitlab.arturbosch.detekt.cli.CliArgs
import io.gitlab.arturbosch.detekt.cli.createSpec
import io.gitlab.arturbosch.detekt.cli.MultipleExistingPathConverter
import java.nio.file.Paths

class ConfigExporter(
private val arguments: CliArgs,
private val outputPrinter: Appendable,
private val errorPrinter: Appendable,
) : Executable {

override fun execute() {
val configPath = Paths.get(arguments.config ?: "detekt.yml")
val spec = arguments.createSpec(outputPrinter, errorPrinter)
DefaultConfigurationProvider.load(spec).copy(configPath)
val spec = ProcessingSpec {
extensions {
disableDefaultRuleSets = arguments.disableDefaultRuleSets
fromPaths { arguments.plugins?.let { MultipleExistingPathConverter().convert(it) }.orEmpty() }
}
}
DefaultConfigurationProvider.load(spec.extensionsSpec).copy(configPath)
outputPrinter.appendLine("Successfully copied default config to ${configPath.toAbsolutePath()}")
}
}
Expand Up @@ -4,23 +4,18 @@ import io.github.detekt.test.utils.NullPrintStream
import io.github.detekt.test.utils.createTempFileForTest
import io.gitlab.arturbosch.detekt.cli.parseArguments
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import java.nio.file.Files

class ConfigExporterSpec {

@Nested
inner class `config exporter` {
@Test
fun `should export the given config`() {
val tmpConfig = createTempFileForTest("ConfigPrinterSpec", ".yml").also { Files.delete(it) }
val cliArgs = parseArguments(arrayOf("--config", tmpConfig.toString()))

@Test
fun `should export the given config`() {
val tmpConfig = createTempFileForTest("ConfigPrinterSpec", ".yml")
val cliArgs = parseArguments(arrayOf("--config", tmpConfig.toString()))
ConfigExporter(cliArgs, NullPrintStream()).execute()

ConfigExporter(cliArgs, NullPrintStream(), NullPrintStream()).execute()

assertThat(Files.readAllLines(tmpConfig)).isNotEmpty
}
assertThat(Files.readAllLines(tmpConfig)).isNotEmpty
}
}
Expand Up @@ -33,7 +33,7 @@ class ProcessingSettings(
LoggingAware by LoggingFacade(spec.loggingSpec),
PropertiesAware by PropertiesFacade(),
EnvironmentAware by EnvironmentFacade(spec.projectSpec, spec.compilerSpec),
ClassloaderAware by ExtensionFacade(spec.extensionsSpec),
ClassloaderAware by ExtensionFacade(spec.extensionsSpec.plugins),
SetupContext {

override val configUris: Collection<URI> = spec.configSpec.extractUris()
Expand Down
Expand Up @@ -14,11 +14,11 @@ interface ClassloaderAware {
}

class ExtensionFacade(
private val extensionsSpec: ExtensionsSpec
private val plugins: ExtensionsSpec.Plugins?
) : AutoCloseable, Closeable, ClassloaderAware {

init {
extensionsSpec.plugins?.paths?.forEach {
plugins?.paths?.forEach {
require(Files.exists(it)) { "Given plugin ‘$it’ does not exist." }
require(it.toString().endsWith("jar")) { "Given plugin ‘$it’ is not a JAR." }
}
Expand All @@ -28,7 +28,6 @@ class ExtensionFacade(
* Shared class loader used to load services from plugin jars.
*/
override val pluginLoader: ClassLoader by lazy {
val plugins = extensionsSpec.plugins
when {
plugins?.loader != null -> checkNotNull(plugins.loader)
plugins?.paths != null -> {
Expand All @@ -46,7 +45,7 @@ class ExtensionFacade(
}

override fun closeLoaderIfNeeded() {
if (extensionsSpec.plugins?.paths != null) {
if (plugins?.paths != null) {
// we created a classloader and need to close it
closeQuietly(pluginLoader as? URLClassLoader)
}
Expand Down
@@ -1,6 +1,7 @@
package io.gitlab.arturbosch.detekt.core.tooling

import io.github.detekt.tooling.api.DefaultConfigurationProvider
import io.github.detekt.tooling.api.spec.ExtensionsSpec
import io.github.detekt.tooling.api.spec.ProcessingSpec
import io.github.detekt.utils.getSafeResourceAsStream
import io.github.detekt.utils.openSafeStream
Expand All @@ -15,26 +16,26 @@ import java.nio.file.Path
import java.nio.file.StandardCopyOption

class DefaultConfigProvider : DefaultConfigurationProvider {
private lateinit var spec: ProcessingSpec
private lateinit var extensionsSpec: ExtensionsSpec

override fun init(spec: ProcessingSpec) {
this.spec = spec
override fun init(extensionsSpec: ExtensionsSpec) {
this.extensionsSpec = extensionsSpec
}

override fun get(): Config = spec.getDefaultConfiguration()
override fun get(): Config = extensionsSpec.getDefaultConfiguration()

override fun copy(targetLocation: Path) {
Files.copy(configInputStream(spec), targetLocation, StandardCopyOption.REPLACE_EXISTING)
Files.copy(configInputStream(extensionsSpec), targetLocation, StandardCopyOption.REPLACE_EXISTING)
}
}

private fun configInputStream(spec: ProcessingSpec): InputStream {
private fun configInputStream(extensionsSpec: ExtensionsSpec): InputStream {
val outputStream = ByteArrayOutputStream()

requireNotNull(spec.javaClass.getSafeResourceAsStream("/default-detekt-config.yml"))
requireNotNull(extensionsSpec.javaClass.getSafeResourceAsStream("/default-detekt-config.yml"))
.use { it.copyTo(outputStream) }

ExtensionFacade(spec.extensionsSpec).pluginLoader
ExtensionFacade(extensionsSpec.plugins).pluginLoader
.getResourcesAsStream("config/config.yml")
.forEach { inputStream ->
outputStream.bufferedWriter().append('\n').flush()
Expand All @@ -50,6 +51,10 @@ private fun ClassLoader.getResourcesAsStream(name: String): Sequence<InputStream
.map { it.openSafeStream() }
}

fun ProcessingSpec.getDefaultConfiguration(): Config {
private fun ExtensionsSpec.getDefaultConfiguration(): Config {
return YamlConfig.load(configInputStream(this).reader())
}

fun ProcessingSpec.getDefaultConfiguration(): Config {
return extensionsSpec.getDefaultConfiguration()
}
Expand Up @@ -11,11 +11,11 @@ import java.nio.file.Files
class DefaultConfigProviderSpec {
@Nested
inner class `defaultConfigProvider without plugins` {
val spec = createNullLoggingSpec {}
private val extensionsSpec = createNullLoggingSpec {}.extensionsSpec

@Test
fun `gets`() {
val config = DefaultConfigProvider().apply { init(spec) }.get()
val config = DefaultConfigProvider().apply { init(extensionsSpec) }.get()

assertThat(config.parentPath).isNull()
assertThat(config.subConfig("build").valueOrNull<Int>("maxIssues")).isEqualTo(0)
Expand All @@ -25,7 +25,7 @@ class DefaultConfigProviderSpec {
@Test
fun `copies`() {
val path = createTempFileForTest("test", "test")
DefaultConfigProvider().apply { init(spec) }.copy(path)
DefaultConfigProvider().apply { init(extensionsSpec) }.copy(path)

assertThat(path)
.hasSameTextualContentAs(resourceAsPath("default-detekt-config.yml"))
Expand All @@ -34,15 +34,15 @@ class DefaultConfigProviderSpec {

@Nested
inner class `defaultConfigProvider with plugins` {
val spec = createNullLoggingSpec {
private val extensionsSpec = createNullLoggingSpec {
extensions {
fromPaths { listOf(resourceAsPath("sample-rule-set.jar")) }
}
}
}.extensionsSpec

@Test
fun `gets`() {
val config = DefaultConfigProvider().apply { init(spec) }.get()
val config = DefaultConfigProvider().apply { init(extensionsSpec) }.get()

assertThat(config.parentPath).isNull()
assertThat(config.subConfig("build").valueOrNull<Int>("maxIssues")).isEqualTo(0)
Expand All @@ -52,7 +52,7 @@ class DefaultConfigProviderSpec {
@Test
fun `copies`() {
val path = createTempFileForTest("test", "test")
DefaultConfigProvider().apply { init(spec) }.copy(path)
DefaultConfigProvider().apply { init(extensionsSpec) }.copy(path)

val actual = String(Files.readAllBytes(path), Charsets.UTF_8)
val expected = String(Files.readAllBytes(resourceAsPath("default-detekt-config.yml")), Charsets.UTF_8) +
Expand Down
6 changes: 3 additions & 3 deletions detekt-tooling/api/detekt-tooling.api
Expand Up @@ -11,12 +11,12 @@ public abstract interface class io/github/detekt/tooling/api/DefaultConfiguratio
public static final field Companion Lio/github/detekt/tooling/api/DefaultConfigurationProvider$Companion;
public abstract fun copy (Ljava/nio/file/Path;)V
public abstract fun get ()Lio/gitlab/arturbosch/detekt/api/Config;
public abstract fun init (Lio/github/detekt/tooling/api/spec/ProcessingSpec;)V
public abstract fun init (Lio/github/detekt/tooling/api/spec/ExtensionsSpec;)V
}

public final class io/github/detekt/tooling/api/DefaultConfigurationProvider$Companion {
public final fun load (Lio/github/detekt/tooling/api/spec/ProcessingSpec;Ljava/lang/ClassLoader;)Lio/github/detekt/tooling/api/DefaultConfigurationProvider;
public static synthetic fun load$default (Lio/github/detekt/tooling/api/DefaultConfigurationProvider$Companion;Lio/github/detekt/tooling/api/spec/ProcessingSpec;Ljava/lang/ClassLoader;ILjava/lang/Object;)Lio/github/detekt/tooling/api/DefaultConfigurationProvider;
public final fun load (Lio/github/detekt/tooling/api/spec/ExtensionsSpec;Ljava/lang/ClassLoader;)Lio/github/detekt/tooling/api/DefaultConfigurationProvider;
public static synthetic fun load$default (Lio/github/detekt/tooling/api/DefaultConfigurationProvider$Companion;Lio/github/detekt/tooling/api/spec/ExtensionsSpec;Ljava/lang/ClassLoader;ILjava/lang/Object;)Lio/github/detekt/tooling/api/DefaultConfigurationProvider;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This functions were introduced in 1.20 so it's safe to change them.

}

public abstract interface class io/github/detekt/tooling/api/Detekt {
Expand Down
@@ -1,13 +1,13 @@
package io.github.detekt.tooling.api

import io.github.detekt.tooling.api.spec.ProcessingSpec
import io.github.detekt.tooling.api.spec.ExtensionsSpec
import io.gitlab.arturbosch.detekt.api.Config
import java.nio.file.Path
import java.util.ServiceLoader

interface DefaultConfigurationProvider {

fun init(spec: ProcessingSpec)
fun init(extensionsSpec: ExtensionsSpec)

fun get(): Config

Expand All @@ -16,9 +16,12 @@ interface DefaultConfigurationProvider {
companion object {

fun load(
spec: ProcessingSpec,
extensionsSpec: ExtensionsSpec,
classLoader: ClassLoader = DefaultConfigurationProvider::class.java.classLoader,
): DefaultConfigurationProvider =
ServiceLoader.load(DefaultConfigurationProvider::class.java, classLoader).first().apply { init(spec) }
): DefaultConfigurationProvider {
return ServiceLoader.load(DefaultConfigurationProvider::class.java, classLoader)
.first()
.apply { init(extensionsSpec) }
}
}
}
@@ -1,16 +1,8 @@
package io.github.detekt.tooling.api

import io.github.detekt.test.utils.createTempFileForTest
import io.github.detekt.tooling.api.spec.BaselineSpec
import io.github.detekt.tooling.api.spec.CompilerSpec
import io.github.detekt.tooling.api.spec.ConfigSpec
import io.github.detekt.tooling.api.spec.ExecutionSpec
import io.github.detekt.tooling.api.spec.ExtensionId
import io.github.detekt.tooling.api.spec.ExtensionsSpec
import io.github.detekt.tooling.api.spec.LoggingSpec
import io.github.detekt.tooling.api.spec.ProcessingSpec
import io.github.detekt.tooling.api.spec.ProjectSpec
import io.github.detekt.tooling.api.spec.ReportsSpec
import io.github.detekt.tooling.api.spec.RulesSpec
import io.gitlab.arturbosch.detekt.api.Config
import org.assertj.core.api.Assertions.assertThatCode
import org.junit.jupiter.api.Nested
Expand All @@ -33,7 +25,7 @@ class DefaultConfigurationProviderSpec {
}

internal class TestConfigurationProvider : DefaultConfigurationProvider {
override fun init(spec: ProcessingSpec) {
override fun init(extensionsSpec: ExtensionsSpec) {
// no-op
}

Expand All @@ -44,23 +36,11 @@ internal class TestConfigurationProvider : DefaultConfigurationProvider {
}
}

private object Spec : ProcessingSpec {
override val baselineSpec: BaselineSpec
private object Spec : ExtensionsSpec {
override val disableDefaultRuleSets: Boolean
get() = error("No expected call")
override val compilerSpec: CompilerSpec
get() = error("No expected call")
override val configSpec: ConfigSpec
get() = error("No expected call")
override val executionSpec: ExecutionSpec
get() = error("No expected call")
override val extensionsSpec: ExtensionsSpec
get() = error("No expected call")
override val rulesSpec: RulesSpec
get() = error("No expected call")
override val loggingSpec: LoggingSpec
get() = error("No expected call")
override val projectSpec: ProjectSpec
get() = error("No expected call")
override val reportsSpec: ReportsSpec
override val plugins: ExtensionsSpec.Plugins?
get() = null
override val disabledExtensions: Set<ExtensionId>
get() = error("No expected call")
}