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

Add config generator for custom rules #5080

Merged
merged 9 commits into from Sep 12, 2022
Expand Up @@ -38,6 +38,12 @@ class DetektPrinter(private val arguments: GeneratorArgs) {
}
}

fun printCustomRuleConfig(pages: List<RuleSetPage>, folder: String) {
yamlWriter.write(Paths.get(folder), "config") {
ConfigPrinter.printCustomRuleConfig(pages)
}
}

private fun markdownHeader(ruleSet: String): String {
check(ruleSet.length > 1) { "Rule set name must be not empty or less than two symbols." }
return """
Expand Down
Expand Up @@ -39,4 +39,34 @@ class Generator(

outPrinter.println("\nGenerated all detekt documentation in $time ms.")
}

fun executeCustomRuleConfig() {
val parser = KtCompiler()
val time = measureTimeMillis {
val ktFiles = arguments.inputPath
.flatMap { parseAll(parser, it) }

val folderMap = mutableMapOf<KtFile, String>()
ktFiles.forEach { ktFile ->
val pathParts = ktFile.name.split("/src/main/kotlin")
if (pathParts.count() > 1) {
folderMap[ktFile] = "${pathParts.first()}/src/main/resources/config/"
}
}

folderMap
.toList()
.groupBy { (_, folder) -> folder }
.toList()
.forEach { (folder, list) ->
val collector = DetektCollector()
list.forEach { (file, _) ->
collector.visit(file)
}
printer.printCustomRuleConfig(collector.items, folder)
}
}

outPrinter.println("\nGenerated custom rules config in $time ms.")
}
}
Expand Up @@ -16,21 +16,21 @@ class GeneratorArgs {

@Parameter(
names = ["--documentation", "-d"],
required = true,
required = false,
description = "Output path for generated documentation."
)
private var documentation: String? = null

@Parameter(
names = ["--config", "-c"],
required = true,
required = false,
description = "Output path for generated detekt config."
)
private var config: String? = null

@Parameter(
names = ["--cli-options"],
required = true,
required = false,
description = "Output path for generated cli options page."
)
private var cliOptions: String? = null
Expand All @@ -42,6 +42,14 @@ class GeneratorArgs {
)
var help: Boolean = false

@Parameter(
names = ["--generate-custom-rule-config", "-gcrc"],
required = false,
description = "Generate config for user-defined rules. " +
"Path to user rules can be specified with --input option"
)
var generateCustomRuleConfig: Boolean = false

val inputPath: List<Path> by lazy {
checkNotNull(input) { "Input parameter was not initialized by jcommander!" }
.splitToSequence(",", ";")
Expand Down
Expand Up @@ -17,6 +17,11 @@ fun main(args: Array<String>) {
exitProcess(0)
}

if (options.generateCustomRuleConfig) {
Generator(options).executeCustomRuleConfig()
return
}

require(Files.isDirectory(options.documentationPath)) { "Documentation path must be a directory." }
require(Files.isDirectory(options.configPath)) { "Config path must be a directory." }

Expand Down
Expand Up @@ -24,6 +24,13 @@ object ConfigPrinter : DocumentationPrinter<List<RuleSetPage>> {
}
}

fun printCustomRuleConfig(item: List<RuleSetPage>): String {
return yaml {
item.sortedBy { it.ruleSet.name }
.forEach { printRuleSetPage(it) }
}
}

private fun defaultBuildConfiguration(): String = """
build:
maxIssues: 0
Expand Down
@@ -0,0 +1,52 @@
package io.gitlab.arturbosch.detekt.generator.printer

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths

class GeneratorSpec {
@Test
fun `config files generated successfully`() {
assertThat(File("$folder1$configPath")).exists()
assertThat(File("$folder2$configPath")).exists()
}

@Test
fun `config files have proper content`() {
assertThat(File("$folder1$configPath").readText())
.contains("complexity:")
.doesNotContain("coroutines:")

assertThat(File("$folder2$configPath").readText())
.contains("coroutines:")
.doesNotContain("complexity:")
}

companion object {
private const val folder1 = "../detekt-rules-complexity"
private const val folder2 = "../detekt-rules-coroutines"
private const val configPath = "/src/main/resources/config/config.yml"

@JvmStatic
@BeforeAll
fun init() {
val args = arrayOf(
"--generate-custom-rule-config",
"--input",
"$folder1, $folder2",
)
io.gitlab.arturbosch.detekt.generator.main(args)
}

@JvmStatic
@AfterAll
fun tearDown() {
Files.deleteIfExists(Paths.get(folder1, configPath))
Files.deleteIfExists(Paths.get(folder2, configPath))
}
}
}