:mega: Help us improve the Gradle Kotlin DSL for b...
# announcements
a
πŸ“£ Help us improve the Gradle Kotlin DSL for build setup! We’re working to make using the Gradle Kotlin DSL as a build tool easier. Please complete this survey to share your feedback with the team: πŸ‘‰ https://kotl.in/slack-gradle-survey πŸ‘ˆ
πŸ‘ 3
πŸ‘€ 2
K 15
v
You are mixing up terminology in that survey and thus contribute to the confusion about these terms. 😞 "Using the Gradle convention plugin" => This links to the section about precompiled script plugins. Besides that "the ... plugin" is not fully correct, convention plugins != precompiled script plugins. Convention plugins are plugins that apply your conventions (own configuration, applied plugins, ...) but you can implement them in any way you like, with Java, Groovy, Kotlin (normal .kt plugins), any other JVM language, legacy script plugins, or also as precompiled script plugins. Precompiled script plugins are the ones that are in
...gradle.kts
files and are most often used to implement convention plugins, but you can as well develop and publish a "normal" plugin with them. "Using included builds for build logic (e.g. buildSrc)" =>
buildSrc
is not an included build. It behaves in many regards very similar to an included build and more so since Gradle 8, but it still is not a real included build, but a special thing that is a bit different in some nuances to an included build.
πŸ‘ 6
a
Thanks for feedback! Let me ping the team
l
Interested in replying to that after the survey is fixed
c
If possible, I'd like to emphasize that the Kotlin DSL should stay as close as possible to the conventions of the broader Gradle ecosystem. The fact that the Kotlin Multiplatform plugin declares dependencies completely differently than any other plugin is probably a necessary evil, but it is already a massive cause of confusion (at least in the teams I've seen). Any and all such differences make the DSL much harder to understand and to use, both to novice and experienced users. If you plan on making large changes to the DSL based on the results of this survey, please keep this in mind.
βž• 1
v
Actually, it is not so much different to what the built-in test suites plugin does. Both have the same problem, that by adding a container element at build script time configurations are created ad-hoc and thus do not have type-safe accessors that can be used in the top-level
dependencies { ... }
block And both provide the same conceptual solution to have a nested
dependencies { ... }
block where you then can use the uniform
implementation
,
compileOnly
, and so on. The main problem is, that KMP had this before and has a slightly different API in the details which is one of the major concerns I've seen with it, as you were not able to use
platform(...)
or
testFIxtures(...)
and so on. The same was true for the test suites nested block, but there is was fixed in 7.6. Imho the KMP plugin should migrate to the same API the test suites plugin is using, that would make them work the same and hopefully remove some of the confusion.
βž• 4
m
Same. I also like that the dependencies are more organized vs putting everything in a top-level
dependencies {}
block.
v
That has its pros and cons, but actually you can also anytime prefer using the top-level
dependencies { ... }
block. You just have to get the configuration by name or use the string-y method call. You are not forced to use the nested block.
m
If I wanted to do things by strings I would do Javascript πŸ˜›
v
by name != by string
Copy code
val jvmImplementation by configurations
dependencies {
    jvmImplementation(...)
}
Using
"jvmImplementation"(...)
is just an alternative for the ones liking it ugly πŸ˜„
πŸ˜„ 1
🫠 1
m
I'd argue that the
by
delegation is still not very typesafe but yea personal preferences
πŸ‘ 1
c
> You are not forced to use the nested block. Indeed, but knowing that requires understanding what configurations are, how they are created, and how the KMP plugin works internally. For the novice, it remains that
implementation
with KMP and with Kotlin/JVM are in theory the same yet have different syntaxes. And even then I'd argue it's a bad idea, if only because it goes against the standard of how everyone else is doing it.
βž• 1
m
it goes against the standard of how everyone else is doing it
who is everyone? KSP and the java plugin?
Feels like Kotlin is in a spot where it can make the standard slowly improve?
c
I meant, how many KMP projects have you seen that declare dependencies in the top-level
dependencies
block? I haven't seen one, except specifically for
platform
declarations
v
That would be very strange indeed
Why should you declare dependencies in the repositories block? πŸ˜„
c
Ouch, typo sorry 😒
m
The question is whether we want configuration names to be public API
I like it to be implementation detail
v
I'd say they are, whether you want it or not. πŸ˜„
βž• 2
m
You can hide them if you create them outside of
Plugin.apply
c
To be clear, I don't really mind that KMP declares dependencies in another place than the top-level block. What I don't like: β€’ The
implementation
in the top-level block and in the
commonMain.dependencies
is not the same, and doesn't have the same options β€’ Some source sets have additional options (
npm
for JS), but you can't check that typesafely β€’ You can't add different options for a specific source set/platform (example)
v
You can hide them if you create them outside of
Well, not hidden, just not having a generated accessor
m
Right. You can always get a reference with
project.configurations.getByName("implementation")
and TBH I'm not a fan of this
Plugins sharing a huge mutable state is dangerous
Considering the configuration name an implementation detail avoids unwanted side effects
(even if it will leak through
ConfigurationContainer
for the foreseeable future)
c
I think that ship has sailed, the very existence of
Named
means that essentially any Gradle domain object's assigned name is part of the public API, that's the main way they are accessed
m
I would love us to evolve the best practice there. Just because you can do
configurations.getByName("foo").somethingThatMutatesTheConfiguration()
doesn't mean you should.
l
I prototyped a new way to declare dependencies for KMP projects, I want to finalize that, publish the Gradle plugin update and show it to you.
πŸ‘€ 2
m
Ideally, I'd love to have mutable & immutable
Configurations
. The plugin creating the
Configuration
would get a mutable reference and can change it. Everywhere else, it's immutable.
v
That would then qualify as doing it differently than everyone else though, unless this is added in Gradle core. :-D
m
Exactly πŸ™‚
"Just" change the configuration API πŸ™‚
πŸ˜… 2
c
I agree, if this is added, it should be in core πŸ™‚
t
> Imho the KMP plugin should migrate to the same API the test suites plugin is using, that would make them work the same and hopefully remove some of the confusion. Until Gradle 8.7 there was no public API to do that. But we definitely want to fix this problem with KMP dependencies configuration
❀️ 2
"Using the Gradle convention plugin" => This links to the section about precompiled script plugins. Besides that "the ... plugin" is not fully correct, convention plugins != precompiled script plugins.
Convention plugins are plugins that apply your conventions (own configuration, applied plugins, ...) but you can implement them in any way you like, with Java, Groovy, Kotlin (normal .kt plugins), any other JVM language, legacy script plugins, or also as precompiled script plugins.
Precompiled script plugins are the ones that are in ...gradle.kts files and are most often used to implement convention plugins, but you can as well develop and publish a "normal" plugin with them.
While you are technically correct here, Gradle documentation itself does not mention what is the "convention plugin". The only place I found is this where only precompiled script plugin is used as an example. So for the average user which is not so familiar with Gradle "convention plugin" == "precompiled script plugin". Though we will update the question here to use "precompiled script plugins" as an example of convention plugins.
"Using included builds for build logic (e.g. buildSrc)" => buildSrc is not an included build. It behaves in many regards very similar to an included build and more so since Gradle 8, but it still is not a real included build, but a special thing that is a bit different in some nuances to an included build.
Here you need to be a really advanced Gradle user to know such nuances. Even Gradle documentation itself says:
The directory buildSrc is treated as an included build.
Here as well we will update the question. fyi @Oleg Nenashev regarding Gradle documentation
updated form should be already available
πŸ™Œ 1
πŸ™ŒπŸΌ 1
v
Gradle documentation itself does not mention what is the "convention plugin". The only place I found is this where only precompiled script plugin is used as an example.
https://docs.gradle.org/current/userguide/sharing_build_logic_between_subprojects.html#sec:convention_plugins defines:
We can write a plugin that encapsulates the build logic common to several subprojects in a project. This kind of plugin is called a convention plugin.
While it is true, that also on that page only precompiled script plugins are used as example, but not as part of the definition. πŸ™‚
So for the average user which is not so familiar with Gradle "convention plugin" == "precompiled script plugin".
Yes, doesn't make it more correct though. πŸ˜„
updated form should be already available
πŸ‘Œ ❀️
πŸ‘πŸ» 1
p
the main issue gradle is an old man
❓ 1