I have a custom Gradle plugin which adds different...
# gradle
l
I have a custom Gradle plugin which adds different common dependencies. However I cannot find the syntax for adding a dependency on another project. In Kotlin Gradle Script DSL the syntax would be:
Copy code
testImplementation(project(":myProject"))
I need the syntax for writing a Kotlin plugin:
Copy code
project.dependencies.add("testImplementation", /* How do I create a project dependency notation here? */)
j
It is the same in Kotlin DSL -
project(":myProject")
Which error are you getting if you do that?
l
I need the syntax for a custom Gradle plugin, not for the Kotlin Script DSL.
j
Got it. Is the Plugin written in Java or Kotlin?
l
In Kotlin
message has been deleted
This is what I get now
j
The
project()
method is on the
Project
interface. So you can do
project.project(...)
l
😄
Works!
Thanks for your help 🙏
j
You can use Kotlin’s
with
to have the whole method in the
project
context, then it looks like in the DSL. E.g.:
Copy code
override fun apply(project: Project): Unit = with(project) {
   ...
}
l
Yes, that's true
j
l
I was looking for some hint about it in the Gradle documentation, but it was not so easy to find.
I usually work only with the Kotlin DSL and there I think the
Project
is indeed always the implicit receiver for the whole syntax. I was not aware of this (because the DSL is so convenient that I never actually thought how it works under the hood and how it connects to the underlying Gradle Java API).
The samples are helpful, thanks!
v
Does it really work with
project.project(...)
? I thought it should be
project.dependencies.project(...)
.
project(...)
in a build script uses the latter (just navigate to it from a build script)
project.project
returns a
Project
while
project.dependencies.project
returns a
ProjectDependency
. Latest if you need to supply a configuration to depend on, you need to use
project.dependencies.project
even if it otherwise works with
project.project
.
l
Good point.
DependencyHandler.add()
just accepts
Object
...
Currently I do this in my plugin and it works (clean + build + tests pass):
Copy code
override fun apply(project: Project) {
        with(project) {
            dependencies.add("testImplementation", project(":testFixtures"))
        }
    }
v
Yeah, because you can give it a variety of things like
ProjectDependency
,
String
and others. I'm not sure whether it accepts
Project
, could well be, I just was not aware
Well, then it seems to accept it unless you need a specific configuration
TIL
l
I mean it doesn't make it typesafe...
There could be an overload for special cases like
String
And the rest of dependency types could be handled just under a common interface like
Dependency
v
I have no idea why the Gradle guys designed it like that. Maybe because main usage target was Groovy DSL as sole DSL at that time and there you have duck-typing anyway.
l
True
That might have been the reason
v
But could also be a different reason. If you are curious, open a feature request to make the API type-safe with overloads and we will see what the Gradle guys respond :-)
l
project.dependencies.project()
doesn't allow String as argument:
v
Well, you can either use the Kotlin DSL classes that add that sugar, or you have to use the real arguments, which is
Map
project.dependencies.project(mapOf("path" to ":foo"))
But if it works with
project.project
you can also just stick with it, I just was not aware that is accepted.
l
I guess if I want to use the Kotlin DSL inside of my plugin code (which is in the
gradlePlugins
module) I need to somehow add dependency on the Kotlin DSL in this module, right?
Otherwise I cannot import the
DependencyHandler.project()
extension function from
org.gradle.kotlin.dsl.DependencyHandlerExtensions.kt
v
Exactly
l
How do I do this?
v
You can either apply the
kotlin-dsl
plugin if you also want the other bits it does, or there is a helper for it, I have to search for. Probably something like
implementation(kotlinDsl())
l
Looks like there is
implementation(gradleKotlinDsl())
v
Exactly
kotlin-dsl
applies
java-gradle-plugin
,
kotlin-dsl.base
, and
kotlin-dsl.precompiled-script-plugins
plugins
kotlin-dsl.base
plugin applies
embedded-kotlin
, adds
gradleKotlinDsl()
to the dependencies of
compileOnly
and
testImplementation
configurations, and configures the Kotlin DSL compiler plugins for example for proper SAM conversion for
Action
and similar.
So maybe
compileOnly(gradleKotlinDsl())
would be more appropriate as the classes are provided by the runtime environment already.
j
I have it added as dependency and I can't access to
Copy code
import org.gradle.api.artifacts.dsl.project
l
Thank you so much for all your helpful explanations. They really helped me understand what's going on behind the scenes (which is so much better than "just quickly fixing the problem")!
1
import org.gradle.kotlin.dsl.project
j
as a workaround you can use
l
Javier, your import is not importing the extension function.
j
exactly, is what I said
it is not accessible even with
gradleKotlinDsl
l
No, the import is wrong
That's what I mean
Compare to mine
j
ah
j
yeah I copy paste it wrong from an accessor
it works with it then
message has been deleted
l
👍
v
👌
j
I don't understand why
testImplementation
and so on are accessors whose need to be generated instead of being in an interface
I guess they generate even the base ones too and not only the custom ones?
v
They are not base ones, they are coming because of a built-in plugin, but still they come because of a plugin and only if it is applied.
Having the accessors there always would make the build script compile but then fail at runtime, and that's counter-productive.
j
yeah but for example de kotlin dependency handler has implementation api and so on without being autogenerated
v
What do you mean with "the kotlin depedendency handler"?
If you mean doing
implementation(...)
in Kotlin DSL, then try navigating to it and looking at the file path and you will see it is generated.
j
Kotlin sourcesets has its own dependency handler interface
message has been deleted
they aren't generated
v
Well, but they are only useable when the Kotlin plugin is applied. And if it is applied,
implementation
is always usable. So it can also be hard-coded.
Besides that that is JetBrains code, not Gradle code
j
yep