i’ve got a `kotlin-conventions` plugin (precompiled script plugin), that users can put on their app,...
b
i’ve got a
kotlin-conventions
plugin (precompiled script plugin), that users can put on their app, and it will configure kotlin (apply various plugins, imports kotlin bom, configure detekt etc.) the version of the kotlin bom applied is configurable via an extension class, but i’ve run into an issue with kapt. the version of the kotlin plugins (e.g. kapt) applied seems to be fixed, by whatever is added to the plugin build’s classpath. Is there any way to make this configurable? It looks like using kotlin 1.5.31 at runtime, with kapt plugin version 1.4.31 was causing some very strange and unexpected failures. and i’m not sure how to solve this for a generic plugin. i guess the generic question is: is there any way to apply a plugin to a project, where the version of the plugin comes from an extension object, and is not statically defined.
t
kotlin plugin version and kapt version should be the same
b
right, and they are but they aren’t matching the kotlin RUNTIME version of the app, which seems to be an issue
so my plugin has 1.4.31 on its classpath, so its applying those versions. but the runtime version of kotlin is defined by the user of the plugin. applier configuring plugin:
Copy code
myPlugin {
  kotlinVersion = "1.5.31"
}
plugin:
Copy code
plugins { // these versions come from whatever the PLUGIN's build has defined on classpath, in this case 1.4.31
    id("my.java-conventions")
    id("org.jetbrains.kotlin.jvm")
    id("org.jetbrains.kotlin.kapt")
    id("org.jetbrains.kotlin.plugin.spring")
    id("org.jetbrains.kotlin.plugin.jpa")
    id("io.gitlab.arturbosch.detekt")
    id("org.jetbrains.dokka")
}

dependencies {
        implementation(platform("org.jetbrains.kotlin:kotlin-bom:${extension.kotlinVersion}"))
        implementation(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:${extension.kotlinCoroutinesVersion}")
        ...
}
t
if I understanding your problem right, your plugin should add kotlin plugin as
compileOnly
dependency and react on it via
plugin.withId('org.jetbrains.kotlin....') { ... }
b
hmm, but that seems to allow for “Do a Thing When this Plugin Is Applied” - which doesn’t exactly help me, cuz what i need is “apply this plugin WITH THIS version (different than the one on the plugin’s own classpath)”
t
I doubt Gradle allows different plugin versions on the build classpath. Possible solution could be forcing kotlin plugin version via you plugin
b
yeah, my hope was to build a plugin that didn’t have to force a specific runtime kotlin version. it has actually worked fine, until someone decided to and try to use kapt 😄
h
I had exactly the same situation as you and there is no way to achieve exactly that. I ended up doing: set a sensible default in the plugin when no override in the project given... That was not too bad, as we just bumped our versions with the plugin from time to time (that also benefitted another strange limitation WE had because of the runtime we lived in, but yeah) and it was overridable with a property in gradle.properties :) no type safety, but as easy as it could get to solve your Problem. Worked well and no one ever asked
b
well, plugin consumers can override the version of kotlin that gets added to the compile classpath, but not the version of the plugins that get added to the build classpath (afaict)
h
Can one add a dependency to buildscript in the apply method of the convention plugin?
Okay i had to dig a bit more into that, because I wasn't able to remeber how exactly I managed to get around that. So it's not possible for a plugin to programmatically add dependencies to the buildscript classpath where the plugin is applied - that makes sense, as the classpath needs to be resolved before the plugin can be loaded, so, yeah. However, the user can override the dependencies manually - your convention plugin can compile against and ship version 1.3.20 of kotlin and your target project can say classpath { dependencies { classpath("org.jetbrains.kotlinkotlin gradle plugin1.5.20) } } and ./gradlew buildEnvironment shows that the dependency is overriden correctly. You can do that for std, reflect, kapt or any other lib in the same way. Not too nice for the user though. Hopefully I am not completely off here and understood what you wanted to achieve. I also tried to manipulate the buildscript classpath from an init script (as that could be abstracted away with a plugin too), but it simply didn't do anything, so my conclusion is, that one can not abstract that thing away 🙂