detekt / detekt

Static code analysis for Kotlin
https://detekt.dev
Apache License 2.0
6.3k stars 777 forks source link

Override the Kotlin Version on Gradle Kotlin DSL #6198

Open nico-arianto opened 1 year ago

nico-arianto commented 1 year ago

Expected Behavior

Code:

plugins {
    val kotlinVersion = "1.8.22"
    kotlin("jvm") version kotlinVersion
    kotlin("kapt") version kotlinVersion
    kotlin("plugin.spring") version kotlinVersion
    kotlin("plugin.jpa") version kotlinVersion
    id("io.gitlab.arturbosch.detekt") version "1.23.0"
}

detekt {
    kotlinVersion = "1.8.21"
    source.from("src/main")
    buildUponDefaultConfig = true
    allRules = true
}

This line kotlinVersion = "1.8.21" will override the Kotlin version and being used by detekt

Note: Or other alternative approach also can, as long can overcome the Kotlin compatibility issue.

Current Behavior

Code:

plugins {
    val kotlinVersion = "1.8.22"
    kotlin("jvm") version kotlinVersion
    kotlin("kapt") version kotlinVersion
    kotlin("plugin.spring") version kotlinVersion
    kotlin("plugin.jpa") version kotlinVersion
    id("io.gitlab.arturbosch.detekt") version "1.23.0"
}

detekt {
    source.from("src/main")
    buildUponDefaultConfig = true
    allRules = true
}

Gradle Task:

> Task :detekt FAILED
Time elapsed [detekt] : 0s
///// Time Consumption Summary /////
[dependencyCheckAnalyze          ] : 4s
[compileJava                     ] : 1s
[assemble                        ] : 0s
[bootJar                         ] : 0s
[classes                         ] : 0s
[compileKotlin                   ] : 0s
[detekt                          ] : 0s
[jar                             ] : 0s
[kaptGenerateStubsKotlin         ] : 0s
[kaptKotlin                      ] : 0s
[processResources                ] : 0s
[resolveMainClassName            ] : 0s

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':detekt'.
> detekt was compiled with Kotlin 1.8.21 but is currently running with 1.8.22.
  This is not supported. See https://detekt.dev/docs/gettingstarted/gradle#dependencies for more information

Context

detekt didn't locked us to use the latest Kotlin version for other Gradle tasks

3flex commented 1 year ago

Did you check the link shown in the log for details on how to fix this?

Adding a version parameter here won't allow us to override Gradle's dependency resolution rules so I don't see how this will solve the issue.

nico-arianto commented 1 year ago

The solution in https://detekt.dev/docs/gettingstarted/gradle#dependencies, it will cause the dependencies version that we declared in

plugins {
    val kotlinVersion = "1.8.22"
    kotlin("jvm") version kotlinVersion
    ...
}

to be override to 1.8.21, which is the same as

plugins {
    val kotlinVersion = "1.8.21"
    kotlin("jvm") version kotlinVersion
    ...
}

I'm wondering if possible for only detekt task to be able to override the dependencies to specific Kotlin version, but other tasks still using the latest Kotlin version

Or maybe the detekt plugin is using a shaded jar to avoid the Kotlin compatibility issue, if possible.

3flex commented 1 year ago

Can you please share a build scan, a reproducer, or a full copy of the build file? There's most likely an issue with your Gradle config and it will be simpler to explain with more info.

nico-arianto commented 1 year ago

here is the build scan: https://gradle.com/s/sgxok4toctxju

alwyn commented 1 year ago

@nico-arianto I don't know if this is the best way to do this, but I think this works in your project build:

configurations.matching { it.name == "detekt" }.all {
    resolutionStrategy.eachDependency {
        if (requested.group == "org.jetbrains.kotlin") {
            useVersion("1.8.21")
        }
    }
}

I have a multi-project and have to put it in each sub-project. It seems to limit the 1.8.21 dependency to only detekt. Will probably have to keep on using it since this problem will probably still be around when Kotlin goes 1.9 or 2.0.

nico-arianto commented 1 year ago

@alwyn Yes, it's working as I wanted it to. Thanks

I hope this version overridden can be done automatically within this piece of code shortly in the next release

plugins {
    id("io.gitlab.arturbosch.detekt") version "1.23.0"
}
3flex commented 1 year ago

This could be something we look at, but there are a few things to consider. Ultimately though this would just be working around problems caused by build scripts or other plugins, not the detekt plugin itself, and the error message shows a link to documentation that explains what the issue is and how to address it.

I'd rather make changes to the documentation since it seems there's room for improvement - suggestions and PRs are welcome.

nico-arianto commented 1 year ago

@3flex πŸ—’οΈ, yeah, we can modify the documentation first and revisit it for improvement.

want me to close this issue or leave it open?

schowave commented 1 year ago

For me, this finally worked:

project.afterEvaluate {
    configurations["detekt"].resolutionStrategy.eachDependency {
        if (requested.group == "org.jetbrains.kotlin") {
            useVersion("1.8.21")
        }
    }
}
xRomZak commented 1 year ago

Since Kotlin 1.9.0 is released today

detekt was compiled with Kotlin 1.8.21 but is currently running with 1.9.0
3flex commented 1 year ago

Have you read https://detekt.dev/docs/gettingstarted/gradle#dependencies?

This is not a detekt defect. It's an issue with either the Gradle build config or another plugin that's affecting detekt. If the documentation linked above is not clear or doesn't address the issue then we're open to suggestions on how to improve it.

kkocel commented 1 year ago

@3flex The problem with the solution described in the docs is that it is very cumbersome and makes it impossible to get detekt updated automatically by dependabot and other similar tools. I would prefer to have single place where detekt version is specified. I think that shadowing jar could be the best option here.

3flex commented 1 year ago

Ok the docs are obviously not clear, because it's not suggesting to hard code the detekt or Kotlin version anywhere, so auto update with dependabot or renovate should not be an issue at all - I'm not sure why that's the takeaway?

I'm open to suggestions on how to improve it.

Shadow jar will fix the issue but it blows out the size of the artifact, slows down builds, complicates our build setup, and the embeddable Kotlin version can't be reused as a dependency by other libraries on user's machines.

BraisGabin commented 1 year ago

I agree with @3flex here. We need your help to make the documentation more clear. This is not a detekt's issue. This is an issue in how the projects apply the kotlin dependency.

I have my projects with detekt and kotlin and I can update/downgrade any of them at my will without the need of any type of hack or workaround. It just work. BUT if the project's configuration overrides the version that detekt uses πŸ’₯πŸ’₯πŸ’₯ it explodes.

So please help us make this more clear. Show us more examples of how you configure kotlin so we can add more examples... We don't know how to improve that documentation.

kkocel commented 1 year ago

I would be for providing a shadow variant alongside the normal one. If detect can't work with any Kotlin version then it is on detekt plate.

kkocel commented 1 year ago

I've seen similar cases in the past - there was wiremock which used an old jetty that was incompatible with new Spring Boot. What wiremock maintainers did? They provided a standalone version with all dependencies shadowed that just /worked/.

n0rthdev commented 1 year ago

We use the gradle buildSrc to specify our custom plugins. This looks like the following:

plugins {
    `kotlin-dsl`
    `kotlin-dsl-precompiled-script-plugins`
}

repositories {
    gradlePluginPortal() // so that external plugins can be resolved in dependencies section
}

val kotlinVersion = "1.8.21"
val nodePluginVersion = "5.0.0"
val sonarPluginVersion = "4.2.0.3129"
val detektVersion = "1.23.0"
val jacocoToCoberturaVersion = "1.1.2"

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
    implementation("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
    implementation("org.jetbrains.kotlin:kotlin-noarg:$kotlinVersion")
    implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:$detektVersion")

    implementation("com.github.node-gradle:gradle-node-plugin:$nodePluginVersion")

    implementation("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:$sonarPluginVersion")

    implementation("net.razvan:JacocoToCoberturaPlugin:$jacocoToCoberturaVersion")
}

so we only include the kotlin-gradle-plugin in the (most current) version we use for our application. We don't at least not intentionally override the kotlin version for all configurations. (like shown in https://detekt.dev/docs/gettingstarted/gradle/#dependencies)

However, we specify the kotlin language version like this.

val KOTLIN_LANGUAGE = KotlinVersion.KOTLIN_1_8

tasks.withType<KotlinCompile>().configureEach {
    compilerOptions{
        jvmTarget.set(ToolVersions.JVM_TARGET)
        apiVersion.set(ToolVersions.KOTLIN_LANGUAGE)
        languageVersion.set(ToolVersions.KOTLIN_LANGUAGE)
        freeCompilerArgs.add("-Xjvm-default=all-compatibility")
    }
}

I am not sure how helpful this is for you ( @3flex @BraisGabin ) to understand how the this issue might arise for detekt users. Let me know if you need additional information.

credmond-git commented 1 year ago

Hello, would it be possible to get a 1.23.1 with Kotlin 1.9.0 and JDK 20 support? This is currently blocking our projects from upgrading to kotlin 1.9.0. I along with the community would be very appreciative if we could get a 1.23.1 with minimal changes quickly, but that will allow us to run our builds with detekt. instead of waiting weeks for a new build with proper Kotlin 1.9.0 updates for the new features.

3flex commented 1 year ago

@credmond-git can you please open a new issue? Thanks.

Our snapshot version is updated to Kotlin 1.9.0 which supports Java 20 targets so you could try that in the meantime.

arnodel commented 1 year ago

I am not sure I understand the root of the issue discussed, but I am in the current situation. Our project has just be updated to be configured to use Kotlin 1.8.22 (from 1.8.20)

What has changed between 1.22 and 1.23 to make detekt so sensitive to particular versions of Kotlin?

I have followed the link to https://detekt.dev/docs/gettingstarted/gradle/#dependencies but I cannot see that we are in the situation described, so I cannot apply the proposed fix (as far as I understand). It looks as if it is going to be difficult to update detekt from now on for people like me who are unable to dive into the subtleties of gradle configurations.

In future I am not sure how we will be able to keep updating detekt.

xRomZak commented 1 year ago

Update update to Kotlin 1.9.10

detekt was compiled with Kotlin 1.9.0 but is currently running with 1.9.10.
credmond-git commented 1 year ago

Crated a ticket to track Kotlin 1.9.10 support https://github.com/detekt/detekt/issues/6428 (corrected issue)

nico-arianto commented 1 year ago

@credmond-git I think you're referring to #6428

3flex commented 1 year ago

I've had another look at this, and it really reinforced the value of providing reproducers. I was able to quickly identify the issue in this project, only because this ticket referred to this one so I was able to follow the breadcrumbs.

The culprit seems to be the io.spring.dependency-management Gradle plugin.

I would like the following users to please confirm if you are using this plugin and whether this workaround works for you:

configurations.detekt {
    resolutionStrategy.eachDependency {
        if (requested.group == "org.jetbrains.kotlin") {
            useVersion("1.9.0") // Add the version of Kotlin that detekt needs
        }
    }
}

If YES, please πŸ‘ this comment.

If you cannot give a πŸ‘either because you're NOT using Spring, or you are using Spring but the workaround doesn't work, please provide a full standalone reproducer.

Assuming Spring is the culprit this can be mentioned in the CLI error message as well as online docs.

credmond-git commented 1 year ago

I am not using spring, and you can see a reproducer here: https://github.com/gestalt-config/gestalt/tree/test/detekt with a build failure at: https://github.com/gestalt-config/gestalt/actions/runs/6032946662/job/16368897280 The workaround didn't work either. The workaround is at https://github.com/gestalt-config/gestalt/blob/test/detekt/buildSrc/src/main/kotlin/gestalt.kotlin-code-quality-conventions.gradle.kts

3flex commented 1 year ago

@credmond-git a couple of things:

  1. I wasn't clear in the workaround example code. The version to enter is the one that detekt requires (in this case 1.9.0). I've updated my example code above and the docs will be clear on this. Changing your workaround to 1.9.0 looks like it works.
  2. I don't see why the workaround is even required in your case? I removed it and can run ./gradlew detekt without errors. Running that with --scan shows that the build is resolving the correct Kotlin version.
nico-arianto commented 1 year ago

@3flex

it's not related to spring-boot for my case, it's because of kotlin("jvm") version "1.9.0" in my case and [Corrected] it's verified because of spring-boot)

I'm using this workaround for now:

configurations.matching { it.name == "detekt" }.all {
    resolutionStrategy.eachDependency {
        if (requested.group == "org.jetbrains.kotlin") {
            useVersion("1.9.0")
        }
    }
}
credmond-git commented 1 year ago

@3flex Thanks for the help, i corrected it to useVersion("1.9.0") and it seems to work. Now that i am trying it again without the workaround, it seems to be running on the gestalt project. It is failing on a work spring project that uses io.spring.dependency-management so i must have gotten them mixed up. I will try the work around on the spring project tomorrow.

3flex commented 1 year ago

@nico-arianto surely your issue is due to spring? This is from the build scan you uploaded: https://scans.gradle.com/s/sgxok4toctxju/plugins#io.spring.dependency-management-3

nico-arianto commented 1 year ago

@3flex

I will still get the same issue when I create a new Kotlin JVM Gradle project without Spring Boot [Corrected] Kotlin project without spring-boot is working as expected)

3flex commented 1 year ago

Please provide a full reproducer of that case - when you create a new Kotlin JVM Gradle project.

The build scan you provided with the original reported issue would have been caused by the spring dependency management plugin being applied in your project per my link in my last comment.

nico-arianto commented 1 year ago

@3flex

Sorry, the issue didn't happen for a new Kotlin JVM Gradle project without Spring Boot , but looks like it's fine also with Spring Boot πŸ€” [Corrected] it's happen with Spring Boot)

Build Gradle (Kotlin) file:

import org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES

plugins {
    kotlin("jvm") version "1.9.0"
    kotlin("plugin.spring") version "1.9.0"
    application
    id("org.springframework.boot") version "3.1.3"
    id("io.spring.dependency-management") version "1.1.3"
    id("io.gitlab.arturbosch.detekt") version "1.23.1"
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.1")
    detektPlugins("io.gitlab.arturbosch.detekt:detekt-rules-libraries:1.23.1")
    testImplementation(kotlin("test"))
}

dependencyManagement {
    imports {
        mavenBom(BOM_COORDINATES)
    }
}

tasks.test {
    useJUnitPlatform()
}

kotlin {
    jvmToolchain(8)
}

application {
    mainClass.set("MainKt")
}

detekt {
    source.from("src")
    buildUponDefaultConfig = true
    allRules = true
}

Gradle Scan: https://scans.gradle.com/s/cvqfejqktotm2/plugins#io.spring.dependency-management-2

Are we sure it's because of the spring.dependency-management, or it's something else?

Reason: If I tried it with my main project, it still failed, and I needed to use resolutionStrategy to workaround.

[Corrected] It's fine ☝🏼 because it's using Kotlin version 1.9.0 which is compatible with detect 1.23.1

arnodel commented 1 year ago

I cannot test this till next week because I am not working but I will next week

EDIT: the workaround does the job.

On Thu, 31 Aug 2023, 05:58 Matthew Haughton, @.***> wrote:

I've had another look at this, and it really reinforced the value of providing reproducers. I was able to quickly identify the issue in this project https://github.com/parts-picker/parts-picker-web, only because this ticket https://github.com/parts-picker/parts-picker-web/issues/151 referred to this one https://github.com/detekt/detekt/issues/6428 so I was able to follow the breadcrumbs.

The culprit seems to be the io.spring.dependency-management Gradle plugin.

I would like the following users to please confirm if you are using this plugin and whether this workaround works for you:

configurations.detekt { resolutionStrategy.eachDependency { if (requested.group == "org.jetbrains.kotlin") { useVersion("1.9.10") // Add the appropriate Kotlin version here } } }

If YES, please πŸ‘ this comment.

If you cannot give a πŸ‘either because you're NOT using Spring, or you are using Spring but the workaround doesn't work, please provide a full standalone reproducer.

Assuming Spring is the culprit this can be mentioned in the CLI error message as well as online docs.

β€” Reply to this email directly, view it on GitHub https://github.com/detekt/detekt/issues/6198#issuecomment-1700332653, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAMJKOMLTEKI5RKZB5FKE6TXYADWHANCNFSM6AAAAAAZABN6MY . You are receiving this because you were mentioned.Message ID: @.***>

3flex commented 1 year ago

looks like it's fine also with Spring Boot

In that config you are using Kotlin plugins with version 1.9.0 so I guess the spring dependency management plugin aligns to that, which is what detekt 1.23.1 needs.

I'm quite sure that in the cases where we have enough info to confirm that it's due to the spring dependency management plugin. There could be other ways to configure Gradle to override the dependencies of course but this is a case that we can better document.

If I tried it with my main project, it still failed and need to use resolutionStrategy to workaround.

Without a reproducer I can't confirm.

nico-arianto commented 1 year ago

@3flex

Ah yes, I missed updating the Kotlin version to 1.9.10

And, it's verified because of spring-boot dependency management.

Thanks

xRomZak commented 1 year ago

@3flex Yes, we have Gradle multi-module project, where one is modules is spring-boot app with

spring-dependencies = { id = "io.spring.dependency-management", version = "1.1.3" }

Workaround with 1.9.10 doesn't help. I'll try to prepare a reproducer

configurations.detekt {
    resolutionStrategy.eachDependency {
        if (requested.group == "org.jetbrains.kotlin") {
            useVersion("1.9.10") // Add the version of Kotlin that detekt needs
        }
    }
}

Test 2: removed spring-boot submodule and its dependencies.

Execution failed for task ':detektAll'.
> detekt was compiled with Kotlin 1.9.0 but is currently running with 1.9.10.
  This is not supported. See https://detekt.dev/docs/gettingstarted/gradle#dependencies for more information.

detektAll is a custom task defined in a root build.gradle

DetektReports.metaClass.setup = {
  html.required.set(true) // observe findings in your browser with structure and code snippets
  xml.required.set(false) // checkstyle like format mainly for integrations like Jenkins
  txt.required.set(true) // similar to the console output, contains issue signature to manually edit baseline files
  sarif.required.set(false) // standardized SARIF format to support integrations with GitHub Code Scanning
  md.required.set(false) // simple Markdown format
}

def setupDetekt = { Detekt detekt ->
  detekt.jvmTarget = 20
  detekt.languageVersion = '1.9'

  detekt.buildUponDefaultConfig = true
  detekt.allRules = false
  detekt.parallel = true

  detekt.config.setFrom(files("$rootDir/config/detekt/detekt.yml")) // custom config
  detekt.baseline.set(file("$rootDir/config/detekt/baseline.xml")) // suppress already existing issues

  detekt.setSource(file(projectDir))
  detekt.include('**/*.kt')
  detekt.exclude('**/resources/**', '**/build/**')

  detekt.reports.setup()
}

tasks.register('detektAll', Detekt) {
  description = 'Custom detekt task for all modules (with type resolution enabled)'
  classpath = configurations.detekt // Set classpath and JVM target (enables type resolution)
  setupDetekt(it)
}
3flex commented 1 year ago

@xRomZak the best way to help us is to try Kotlin 1.9.10 then respond to this comment, thanks! https://github.com/detekt/detekt/issues/6198#issuecomment-1700332653

xRomZak commented 1 year ago

Updated my comment above. I'll provide more details as soon as possible.

3flex commented 1 year ago

Use useVersion("1.9.0") with detekt 1.23.1.

It needs to be set to what detekt needs.

kkocel commented 1 year ago

I have the following project (generated from spring starter page): https://github.com/kkocel/detektrepro It works on 1.9.0 but when switched to branch https://github.com/kkocel/detektrepro/tree/1910 (Kotlin 1.9.10) it doesn't.

3flex commented 1 year ago

Is that a public repo? I get a 404 on both links

kkocel commented 1 year ago

@3flex I've just changed it to public

3flex commented 1 year ago

@kkocel please see my comment above, you need to apply the workaround withuseVersion("1.9.0")

kkocel commented 1 year ago

@3flex This workaround has lots of downsides - eg. dependabot won't know about this workaround, so I need to update the version in the workaround code every time when detekt updates. Once again, please reconsider providing a version of the detekt plugin with shadowed Kotlin dependency - it will resolve this issue permanently.

BraisGabin commented 1 year ago

OK, so it feels to be confirmed that io.spring.dependency-management generates this issue. (We still don't know if everyone that faced this issue is for that reason so please, keep answering @3flex comment).

But, which should be our action plan for the "incompatibility" with that plugin? Some ideas:

BraisGabin commented 1 year ago

@3flex This workaround has lots of downsides - eg. dependabot won't know about this workaround, so I need to update the version in the workaround code every time when detekt updates. Once again, please reconsider providing a version of the detekt plugin with shadowed Kotlin dependency - it will resolve this issue permanently.

I don't think we should do that. This is not our issue. It is an issue at io.spring.dependency-management. Also, we are asking you to see if the workaround works to be sure that we understand the problem. You don't need to add it to your code base if you don't want.

kkocel commented 1 year ago

Yes, the workaround works but it's lame.

I see things differently - it's the detekt that strictly requires the exact Kotlin version (and breaks otherwise), so yes it's your issue. If detekt so desperately requires the exact Kotlin version then it should bundle it, instead of requiring every other plugin to adjust.

3flex commented 1 year ago

the workaround works

Thanks for confirming!

requiring every other plugin to adjust

This is not what we're saying. There's a workaround that allows you to use detekt & the Spring dependency management plugin together. We are not saying that any other plugin has to adjust. There might also be better workarounds, so any suggestions for improvement to the documented workaround would be welcome. I see the Spring dependency management plugin is configurable so there might be another way to work around if both plugins are in use.

detekt that strictly requires the exact Kotlin version (and breaks otherwise), so yes it's your issue.

detekt interfaces with a lot of core compiler code and it sensitive to the version in use. This is not going to change. If detekt runs with an unexpected Kotlin compiler version that creates other issues, which get raised and have to be investigated. Instead, detekt errors when this is the case, and asks for this to be fixed, so we don't get strange errors being reported. The error is only shown when the build is misconfigured.

In terms of whether this is our issue or not - it's not. detekt's Gradle plugin configures itself correctly. Another plugin is overriding that configuration. That's not for us to fix.

dependabot won't know about this workaround, so I need to update the version in the workaround code every time when detekt updates

To be frank, this is not our problem. detekt needs to run with a certain version of Kotlin in its classpath. If the Spring dependency management plugin clobbers the configuration, that's caused by that plugin, and if the workaround is not ideal or has some other issues, that's really not in our hands.

You are of course free to stop using the Spring dependency management plugin, come up with an improved workaround and suggest improvements to our documentation, or even stop using detekt. Obviously we want as many people as possible to use detekt as many contributors and the maintainers have put a lot of time and effort into making detekt what it is today, and we like to see others getting value from it.

3flex commented 1 year ago

Back to the options we might consider:

Open an issue to io.spring.dependency-management

If anyone's affected by this directly then it's worth raising here. Perhaps the maintainers of that plugin have other suggested workarounds, even if they don't deliver an actual fix.

Update our documentation and explain this problem

Yes, we should definitely do this.

Check on our gradle plugin if this plugin is applied and, if it is, show a different error message. That different error message I don't know if it should point to the issue to io.spring.dependency-management or just print the workaround.

This is a good idea - though we probably don't want to show it every single time. I think it's better to update the CLI error message to reference Spring since it's going to continue being a common source of this issue.

wilkinsona commented 1 year ago

Hi, all. I'm the primary maintainer of the io.spring.dependency-management plugin, I'm also a member of the Spring Boot team. A colleague of mine, @marcingrzejszczak, asked me to take a look at this issue.

If you apply only the dependency management plugin to a project, it won't have any effect at all on the version of Kotlin that's used. If you apply both the dependency management plugin and Spring Boot's plugin, the latter will configure the former to import the spring-boot-dependencies bom and this bom includes dependency management for Kotlin. Furthermore, when you apply a specific version of a Kotlin plugin, Spring Boot's plugin automatically detects that and overrides the managed version of Kotlin to match. This dependency management is applied to every configuration which is why you're seeing an override of the version of Kotlin in the detekt configuration.

Generally speaking, keeping dependency versions consistent across configurations is useful. However, it sounds like that's not the case here. From what I understand reading the above, Detekt itself needs to run using a specific version of Kotlin, irrespective of the version of Kotlin that's being used elsewhere in the same project.

Assuming that I have understood this situation correctly, I'm afraid I don't have any suggestions for a better workaround. It sounds like what's really needed is a way to tell the dependency management plugin that "global" dependency management should not be applied to the detekt configuration. That would leave it free to resolve whatever versions Detekt needs.