From b51a134a3b9875db52f3a933e0abb9dacbd14745 Mon Sep 17 00:00:00 2001 From: Vladyslav Kuksiuk Date: Fri, 24 Jul 2026 12:03:19 +0200 Subject: [PATCH 1/3] Add Detekt. --- PROJECT.md | 3 +- README.md | 4 +- buildSrc/build.gradle.kts | 11 ++++++ .../embedcode/gradle/dependency/Detekt.kt | 37 +++++++++++++++++++ .../src/main/kotlin/jvm-module.gradle.kts | 23 ++++++++++++ config/detekt/baseline.xml | 21 +++++++++++ config/detekt/detekt.yml | 21 +++++++++++ 7 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 buildSrc/src/main/kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt create mode 100644 config/detekt/baseline.xml create mode 100644 config/detekt/detekt.yml diff --git a/PROJECT.md b/PROJECT.md index 85db818..4acdb27 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -19,7 +19,7 @@ Embed Code configuration file and do not need to install the executable or Kotli - `version.gradle.kts`: the plugin version and default Embed Code application version. - `gradle.properties`: Gradle runtime, parallelism, and configuration-cache settings, plus Kotlin style and dependency defaults. -- `buildSrc/`: build settings, dependency coordinates, and the shared `jvm-module` convention. +- `buildSrc/`: build settings, dependency coordinates, and the shared JVM and Detekt convention. - `gradle-plugin/build.gradle.kts`: plugin declaration, generated version source, functional test source set, publication metadata, and Plugin Portal configuration. - `gradle-plugin/src/main/kotlin/`: extension, plugin, task, platform, version, JSON, checksum, @@ -27,6 +27,7 @@ Embed Code configuration file and do not need to install the executable or Kotli - `gradle-plugin/src/main/templates/`: generated default-version source template. - `gradle-plugin/src/test/kotlin/`: focused unit specifications. - `gradle-plugin/src/functionalTest/kotlin/`: TestKit consumer-build specifications. +- `config/detekt/`: project-specific Detekt rules and the baseline for existing findings. - `scripts/check_agent_config.py` and `scripts/tests/`: deterministic validation and tests. - `.github/workflows/check.yml`: agent configuration and Ubuntu and Windows build verification. - `.agents/skills/`: repository engineering, test, writing, review, and security workflows. diff --git a/README.md b/README.md index 47ee963..3da0ebc 100644 --- a/README.md +++ b/README.md @@ -143,8 +143,8 @@ Run compilation, plugin validation, and the complete test suite: ./gradlew check ``` -Fast unit tests run under `test`. TestKit coverage runs separately under -`functionalTest`; the `check` task includes both. +Fast unit tests run under `test`, TestKit coverage runs under `functionalTest`, and Detekt static +analysis runs under `detekt`. The `check` task includes all three. To test the plugin in another project, publish it to the local Maven repository: diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 4fb1bdd..771c92f 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -44,12 +44,23 @@ val kotlinVersion = "2.4.10" */ val pluginPublishVersion = "2.1.1" +/** + * Version of the Detekt Gradle plugin. + * + * `buildSrc` needs this version before its dependency objects are compiled. + * Keep in sync with `io.spine.embedcode.gradle.dependency.Detekt.version`. + */ +val detektVersion = "2.0.0-alpha.5" + dependencies { implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") implementation( "com.gradle.plugin-publish:com.gradle.plugin-publish.gradle.plugin:" + pluginPublishVersion, ) + implementation( + "dev.detekt:dev.detekt.gradle.plugin:$detektVersion", + ) } kotlin { diff --git a/buildSrc/src/main/kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt b/buildSrc/src/main/kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt new file mode 100644 index 0000000..de02d72 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2026, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.spine.embedcode.gradle.dependency + +/** + * Detekt static-analysis plugin used by JVM modules. + */ +object Detekt { + + // The alpha version is used, because latest stable version doesn't support JDK 25. + const val version = "2.0.0-alpha.5" + const val id = "dev.detekt" +} diff --git a/buildSrc/src/main/kotlin/jvm-module.gradle.kts b/buildSrc/src/main/kotlin/jvm-module.gradle.kts index 5291c7a..f709e55 100644 --- a/buildSrc/src/main/kotlin/jvm-module.gradle.kts +++ b/buildSrc/src/main/kotlin/jvm-module.gradle.kts @@ -24,7 +24,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import dev.detekt.gradle.Detekt as DetektTask +import dev.detekt.gradle.extensions.DetektExtension import io.spine.embedcode.gradle.BuildSettings +import io.spine.embedcode.gradle.dependency.Detekt import io.spine.embedcode.gradle.dependency.JUnit import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinVersion @@ -34,6 +37,8 @@ plugins { kotlin("jvm") } +apply(plugin = Detekt.id) + fun jvmTarget(version: Int): JvmTarget = JvmTarget.fromTarget(version.toString()) java { @@ -58,6 +63,24 @@ tasks.withType().configureEach { options.release.set(BuildSettings.bytecodeVersion) } +extensions.configure { + toolVersion.set(Detekt.version) + config.setFrom(rootProject.layout.projectDirectory.file("config/detekt/detekt.yml")) + baseline.set(rootProject.layout.projectDirectory.file("config/detekt/baseline.xml")) + buildUponDefaultConfig.set(true) + source.setFrom( + files( + "src/main/kotlin", + "src/test/kotlin", + "src/functionalTest/kotlin", + ), + ) +} + +tasks.withType().configureEach { + jvmTarget.set(BuildSettings.bytecodeVersion.toString()) +} + dependencies { testImplementation(JUnit.Jupiter.lib) testRuntimeOnly(JUnit.PlatformLauncher.lib) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml new file mode 100644 index 0000000..e4e819e --- /dev/null +++ b/config/detekt/baseline.xml @@ -0,0 +1,21 @@ + + + + + LongMethod:EmbedCodePlugin.kt:EmbedCodePlugin$override fun apply + LongMethod:InstallEmbedCodeTask.kt:InstallEmbedCodeTask$@TaskAction public fun install + MagicNumber:Checksum.kt:3 + MagicNumber:InstallEmbedCodeTask.kt:InstallEmbedCodeTask.Companion$200 + MagicNumber:InstallEmbedCodeTask.kt:InstallEmbedCodeTask.Companion$299 + ReturnCount:Checksum.kt:internal fun githubReleaseApi: URI? + ReturnCount:InstallEmbedCodeTask.kt:InstallEmbedCodeTask$@TaskAction public fun install + ReturnCount:InstallEmbedCodeTask.kt:InstallEmbedCodeTask$private fun installFromVerifiedAsset: Boolean + ReturnCount:InstallEmbedCodeTask.kt:InstallEmbedCodeTask$private fun isLocallyVerifiedExecutable: Boolean + ReturnCount:InstallEmbedCodeTask.kt:InstallEmbedCodeTask$private fun isPreviouslyVerifiedInstallation: Boolean + ThrowsCount:Checksum.kt:internal fun parseGitHubAssetSha256: String + ThrowsCount:EmbedCodeVersion.kt:internal fun validateVersion: String + ThrowsCount:InstallEmbedCodeTask.kt:InstallEmbedCodeTask$@TaskAction public fun install + ThrowsCount:InstallEmbedCodeTask.kt:InstallEmbedCodeTask.Companion$fun createDirectoriesSafely + TooManyFunctions:InstallEmbedCodeTask.kt:InstallEmbedCodeTask$Companion + + diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml new file mode 100644 index 0000000..af5d19f --- /dev/null +++ b/config/detekt/detekt.yml @@ -0,0 +1,21 @@ +complexity: + LargeClass: + excludes: + - '**/test/**' + - '**/functionalTest/**' + TooManyFunctions: + excludes: + - '**/test/**' + - '**/functionalTest/**' + +naming: + FunctionNaming: + excludes: + - '**/test/**' + - '**/functionalTest/**' + +style: + MagicNumber: + excludes: + - '**/test/**' + - '**/functionalTest/**' From 5edea920296c3bdd15e3f963bfbb89a3a9efeede Mon Sep 17 00:00:00 2001 From: Vladyslav Kuksiuk Date: Fri, 24 Jul 2026 12:12:08 +0200 Subject: [PATCH 2/3] Provide better linter rules. --- config/detekt/baseline.xml | 1 - config/detekt/detekt.yml | 51 +++++++++++++------ .../embedcode/gradle/EmbedCodePluginSpec.kt | 5 +- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index e4e819e..b2a38a1 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -4,7 +4,6 @@ LongMethod:EmbedCodePlugin.kt:EmbedCodePlugin$override fun apply LongMethod:InstallEmbedCodeTask.kt:InstallEmbedCodeTask$@TaskAction public fun install - MagicNumber:Checksum.kt:3 MagicNumber:InstallEmbedCodeTask.kt:InstallEmbedCodeTask.Companion$200 MagicNumber:InstallEmbedCodeTask.kt:InstallEmbedCodeTask.Companion$299 ReturnCount:Checksum.kt:internal fun githubReleaseApi: URI? diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index af5d19f..8df5cb9 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -1,21 +1,42 @@ -complexity: - LargeClass: - excludes: - - '**/test/**' - - '**/functionalTest/**' - TooManyFunctions: - excludes: - - '**/test/**' - - '**/functionalTest/**' - naming: + ClassNaming: + excludes: &testFiles + - "**/*Test.kt" + - "**/*Spec.kt" + MatchingDeclarationName: + excludes: *testFiles FunctionNaming: - excludes: - - '**/test/**' - - '**/functionalTest/**' + excludes: *testFiles style: + UnusedPrivateFunction: + allowedNames: '(_|ignored|expected|serialVersionUID|about|ABOUT)' + UnusedPrivateProperty: + allowedNames: '(_|ignored|expected|serialVersionUID|about|ABOUT)' MagicNumber: + excludes: *testFiles + ignoreNumbers: + - '-1' + - '0' + - '1' + - '2' + - '3' + MaxLineLength: + maxLineLength: 100 + excludeCommentStatements: true + ForbiddenComment: + allowedPatterns: 'TODO:' + +complexity: + LargeClass: + excludes: *testFiles + TooManyFunctions: excludes: - - '**/test/**' - - '**/functionalTest/**' + - '**/*Exts.kt' + - '**/*Extensions.kt' + - '**/*View.kt' + - '**/*Projection.kt' + - '**/*Test.kt' + - '**/*Spec.kt' + LongMethod: + excludes: *testFiles diff --git a/gradle-plugin/src/functionalTest/kotlin/io/spine/embedcode/gradle/EmbedCodePluginSpec.kt b/gradle-plugin/src/functionalTest/kotlin/io/spine/embedcode/gradle/EmbedCodePluginSpec.kt index b3c95a6..10d9096 100644 --- a/gradle-plugin/src/functionalTest/kotlin/io/spine/embedcode/gradle/EmbedCodePluginSpec.kt +++ b/gradle-plugin/src/functionalTest/kotlin/io/spine/embedcode/gradle/EmbedCodePluginSpec.kt @@ -1189,8 +1189,9 @@ internal class EmbedCodePluginSpec { server.createContext("/releases/download/") { exchange -> val relativePath = exchange.requestURI.path.removePrefix("/releases/download/") downloads.incrementAndGet() - val asset = releaseDirectory.resolve("download").resolve(relativePath).normalize() - if (!asset.startsWith(releaseDirectory.resolve("download")) || !Files.isRegularFile(asset)) { + val downloadDirectory = releaseDirectory.resolve("download") + val asset = downloadDirectory.resolve(relativePath).normalize() + if (!asset.startsWith(downloadDirectory) || !Files.isRegularFile(asset)) { exchange.sendResponseHeaders(404, -1) } else { val content = Files.readAllBytes(asset) From 703550b1da1726278099f70ee9731182a4e4c3f3 Mon Sep 17 00:00:00 2001 From: Vladyslav Kuksiuk Date: Fri, 24 Jul 2026 14:14:33 +0200 Subject: [PATCH 3/3] Improve readability. --- .../kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt | 1 - buildSrc/src/main/kotlin/jvm-module.gradle.kts | 3 +-- config/detekt/detekt.yml | 4 ---- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/buildSrc/src/main/kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt b/buildSrc/src/main/kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt index de02d72..dbbbf30 100644 --- a/buildSrc/src/main/kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt +++ b/buildSrc/src/main/kotlin/io/spine/embedcode/gradle/dependency/Detekt.kt @@ -33,5 +33,4 @@ object Detekt { // The alpha version is used, because latest stable version doesn't support JDK 25. const val version = "2.0.0-alpha.5" - const val id = "dev.detekt" } diff --git a/buildSrc/src/main/kotlin/jvm-module.gradle.kts b/buildSrc/src/main/kotlin/jvm-module.gradle.kts index f709e55..120bb15 100644 --- a/buildSrc/src/main/kotlin/jvm-module.gradle.kts +++ b/buildSrc/src/main/kotlin/jvm-module.gradle.kts @@ -34,11 +34,10 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { `java-library` + id("dev.detekt") kotlin("jvm") } -apply(plugin = Detekt.id) - fun jvmTarget(version: Int): JvmTarget = JvmTarget.fromTarget(version.toString()) java { diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 8df5cb9..cad7d1d 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -32,10 +32,6 @@ complexity: excludes: *testFiles TooManyFunctions: excludes: - - '**/*Exts.kt' - - '**/*Extensions.kt' - - '**/*View.kt' - - '**/*Projection.kt' - '**/*Test.kt' - '**/*Spec.kt' LongMethod: