I keep bombarding with n00b questions here, but I ...
# gradle
a
I keep bombarding with n00b questions here, but I have trouble figuring it out. Suppose I have the following directories: • plugins ◦ conventions ▪︎ build.gradle.kts ▪︎ settings.gradle.kts ▪︎ src/main/kotlin/... .gradle.kts ◦ starters ▪︎ build.gradle.kts ▪︎ settings.gradle.kts ▪︎ src/main/kotlin/... .gradle.kts • settings.gradle.kts In the root
settings.gradle.kts
I have:
Copy code
includeBuild('plugins/conventions')
includeBuild('plugins/starters')
How can I reference plugins defined in
conventions
in the
starters
project? They are unable to resolve and I have no clue on how to add them to the dependencyResolutionMaangement of
starters
.
h
includeBuild('conventions')
in
settings.gradle.kts
inside
plugins/starters
, I think.
a
what error are you getting?
in Groovy strings can have single quotes, but in Kotlin strings use double quotes also the
includeBuild()
directory needs to be relative
Copy code
// ./plugins/conventions/settings.gradle.kts

includeBuild("../starters")
then I’m pretty sure that the plugins in
plugins/starters
will be auto-included, so in the root you just need
Copy code
// ./settings.gradle.kts

includeBuild("./plugins/conventions")
And if you have any Settings convention plugins (
foo.settings.gradle.kts
) then you need to use
pluginManagement {}
Copy code
pluginManagement {
  includeBuild("../settings-plugins/")
}
p
The questions are also very helpful for others 😉
v
Though actually not the subject of this channel (see the topic) 😉
a
Okay, so here goes. Scenario 1: •
includeBuild("../starters")
in
settings.gradle.kts
of
plugins/conventions/settings.gradle.kts
• Only
includeBuild("./plugins/conventions")
in root
settings.gradle.kts
This results in:
Copy code
starters:test: Cannot resolve external dependency org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 because no repositories are defined.
Required by:
    project :starters
Scenario 2: •
includeBuild("../conventions")
in
settings.gradle.kts
of
plugins/starters/settings.gradle.kts
includeBuild("./plugins/conventions")
and
includeBuild("./plugins/starters")
in root
settings.gradle.kts
This results in:
Copy code
starters:test: Cannot resolve external dependency org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 because no repositories are defined.
Required by:
    project :starters
Scenario 3: • Same as Scenario 2 • But I add the
dependencyResolutionManagement
of
conventions
also in
starters
Result:
Copy code
Plugin [id: 'repositories.conventions'] was not found in any of the following sources:
This is one of my convention plugins I want to use in the starters.
a
try defining repositories in all of the
settings.gradle.kts
Copy code
// settings.gradle.kts

pluginManagement {
  repositories {
    gradlePluginPortal()
    mavenCentral()
  }
}

@Suppress("UnstableApiUsage") // Central declaration of repositories is an incubating feature
dependencyResolutionManagement {

  repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)

  repositories {
    mavenCentral()
    gradlePluginPortal()
  }
}
a
But, in scenario 3 it seems to work, except that it doesn't resolve my own local repositories.conventions plugin of the
conventions
build project
a
what’s the path of the
repositories.conventions
plugin (
src/kotlin/…
?), and what
package
is it in?
a
plugins/conventions/src/main/kotlin/repositories.conventions.gradle.kts
and it contains a block
repositories
which I use in other convention plugins or target project. That works just fine. It just doesn't resolve in another
build
project. I had the starters as part of the
conventions
subproject initially but decided to separate them out.
a
Gradle uses property files to discover plugins. What plugin descriptors are in
./plugins/conventions/build/pluginDescriptors/...
? you’ve applied the
kotlin-dsl
plugin in
./plugins/conventions/build.gradle.kts
, right?
a
The plugin descriptor is there. And it contains:
implementation-class=Repositories_conventionsPlugin
.
a
what’s the filename?
a
repositories.conventions.properties
But that itsn't a problem I think. I can easily apply this plugin in other projects, just not in another precompiled plugin in another subproject. I'll create a minimal example later to maybe isolate the issue and to be able to share code.
a
yeah that looks good
a
Okay, so I created a minimal example: https://github.com/avwie/kotlinx/tree/minimal-gradle-example The issue is is that it appears to build correctly. I can build the individual projects in
/plugins
and they create descriptors. But when I include a starter plugin in an actual project it throws an error (the error being that a convention plugin I reference in a starter plugin can not be found). I can however include the plugins of
conventions
in an example project without problems.
a
so the error is in the
plugins/starters
project. In
plugins/starters/src/main/kotlin/starter.multiplatform.gradle.kts
• it applies the convention plugin
id("convention.repositories")
, but that plugin exists in
plugins/conventions
, so add
includeBuild("../conventions")
to
plugins/starters/settings.gradle.kts
• it applies the Kotlin Multiplatform & Serialization plugins, but the Maven dependencies aren’t added into
plugins/starters/build.gradle.kts
and the error
Plugin with id 'convention.repositories' not found
is shown because the
plugins/conventions
project isn’t building at all (I should see a
plugins/conventions/build
dir, but there isn’t one, therefore the project isn’t building). So Gradle isn’t showing the root cause. because includedBuild projects are completely independent, you can open them up in IntelliJ or terminal and try and build them long story short, this is the wrong Maven coordinate for the KxS plugin
Copy code
gradle-plugin-jetbrains-serialization = { module = "org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin", version.ref = "jetbrains-kotlin" }
That’s the magic Maven coordinate that Gradle uses to match a plugin ID
id("org.jetbrains.kotlin.plugin.serialization")
to the Maven dependency that actually contains the plugin JAR To get the Maven coordinate, look at the plugin page https://plugins.gradle.org/plugin/org.jetbrains.kotlin.plugin.serialization and copy the Maven coordinate from
classpath(...)
in the ‘legacy’ section
a
whoah
Never heard of 'magic Maven coordinates' before
I don’t think you need this. The versions should only be declared once, and since they’re provided by includedBuild plugins, this will probably confuse Gradle
Copy code
// ./build.gradle.kts
plugins {
    @Suppress("DSL_SCOPE_VIOLATION") kotlin("js").version(libs.versions.jetbrains.kotlin).apply(false)
    @Suppress("DSL_SCOPE_VIOLATION") kotlin("jvm").version(libs.versions.jetbrains.kotlin).apply(false)
    @Suppress("DSL_SCOPE_VIOLATION") kotlin("multiplatform").version(libs.versions.jetbrains.kotlin).apply(false)
    @Suppress("DSL_SCOPE_VIOLATION") kotlin("plugin.serialization").version(libs.versions.jetbrains.kotlin).apply(false)
    @Suppress("DSL_SCOPE_VIOLATION") id("org.jetbrains.compose").version(libs.versions.jetbrains.compose).apply(false)
}
a
Yes you are right. I already removed those in another branch
a
hmm now I’m getting this error, but I’m not sure why
Copy code
e: /home/.local/share/gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-serialization/1.8.0/938336470c17e5706f7ab33f2b2ee2fcfacfe80/kotlin-serialization-1.8.0-gradle75.jar!/META-INF/kotlinx-serialization-compiler-plugin.k2.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.8.0, expected version is 1.6.0.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction
   > Compilation error. See log for more details
importing the version catalogs into convention plugins is probably not a good idea
Copy code
val versionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")
there’s no official support for using them, so it will probably cause weird issues. And generally, I don’t think it’s necessary - the versions can be left up to the actual projects because 1. it’s easier to see what versions are used in a subproject if they’re defined locally, 2. it can lead to weird issues if two plugins want to use two different versions, and 3. if ever a project wants to ‘opt out’ of a version, it could be really tricky
a
So how would that work? How can I reference to an
implementation
dependency then in a library plugin?
a
that’s what I’m saying, don’t haha
I think another problem is the plugin names: they contain
.
, and for some reason that’s making either Kotlin or Gradle confused
Module was compiled with an incompatible version of Kotlin
this was caused by me opening the projects in IntelliJ which auto-downloaded Gradle 7.5.1, but the root project has 7.6. So I copied the Gradle wrapper files from the root project.
so 1. rename
convention.repositories.gradle.kts
to
repositories.gradle.kts
2. add
package convention
at the top
a
So the idea is that convention plugins should not have implementations in them? Hmm... that really limits the use-case for convention plugins actually for me. Especially since that was recommended way of doing it actually in earlier threads.
a
I don’t think that convention plugins should have dependencies in them - but that’s my general advice, and it depends on the situation
for larger projects version management I use
libs.versions.toml
to centralise the definitions, and create a
java-version-platform
subproject for version alignment. Then in the version-platform I use the
libs.versions.toml
to add all the BOMs or other dependencies, and in all subprojects import the version-platform, and again use
libs.versions.toml
to add specific dependencies.
then if I do add dependencies in any convention plugins, they don’t need to have the version defined - that will be provided by the version-platform
alright I’m still getting the
Plugin with id 'convention.repositories' not found
but I can’t figure out why. My guess is that chaining two includedBuilds doesn’t pass along plugin IDs. Do you really need two separate includedBuild projects for convention plugins?
this might have something to do with it https://docs.gradle.org/current/userguide/composite_builds.html#included_plugin_builds
Including plugin builds via the plugin management block is an incubating feature. You may also use the stable
includeBuild
mechanism outside
pluginManagement
to include plugin builds. However, this does not support all use cases and including plugin builds like that will be deprecated once the new mechanism is stable.
a
No I don’t need it, it was just an experiment I was running. Mind you, this is not for a production or company wide project. This is for learning and understanding and making my own experiments in Kotlin easier to setup
So I appreciate all your help! But you shouldn’t spent your Sunday on debugging a random strangers Gradle experimenting;)
p
The discussion is very valuable for me, just no time to follow it completely today. Need to look on it tomorrow. What are the limitations of convention plugins is a question I also think about currently
a
my pleasure :) Going over this stuff is a fun challenge
if you want to see how I setup a large Gradle project with includedBuild convention plugins,
libs.versions.toml
, version-catalog etc in a large project, take a look at https://github.com/adamko-dev/kafkatorio/ (although it is quite messy)
I also did the Gradle config for https://github.com/Kantis/ks3, which I think is a pretty good template for setting up a Kotlin Multiplatform project with publishing. It uses includedBuild plugins.
111 Views