This message was deleted.
# community-support
s
This message was deleted.
t
I suppose this is one of the few cases where you still have to use
afterEvaluate
. Alternatively, don't use a property but a method: when the method is called is when you actually configure the
gradlePlugin {}
.
๐Ÿ‘ 2
m
Ah yes, method will work, thanks !
Trying to avoid all the
afterEvaluate{}
...
I'm almost there ๐Ÿ™‚
c
I did the method "trick" quite a few times to skip using afterEvaluate too
a
Alternatively I would question the value of abstracting the gradlePlugin extension configuration behind your convention plugin. I get the allure, but trying to hide an extension with an extension doesnt seem to get you a whole lot. If a project that applies your convention plugin contains multiple plugins in the same source, then they would need to specify publishing options for one, and then use the gradleExtension themselves to add the additional ones.
๐Ÿ‘€ 1
๐Ÿ‘ 1
If a consumer of the convention plugin has to configure an extension or call some custom method anyways, they might as well configure the extension from Gradle. Unless it can be fully hidden and configured for the end users, I wouldn't try to obscure the Gradle model with your own custom model. You are only saving a few lines of code for every user, but at the cost of additional classes and a custom extension model. I've tried to do this type of thing for the majority of different Java projects we have at our organization (Gradle plugins, maven jars, applications, etc) and every time I tried to push the convention plugins a little too far, I ended up regretting it.
m
Fair point. It's only two projects so far but I liked the idea of a single entry point. Without this, it's hard to tell what needs to be configured without extra doc
Like how would consumers know they need to configure
gradlePlugin{}
a
How are they gonna know they need to configure myPublishing? Same problem really.
The way I do this personally, is do some extension validation in the afterEvaluate and throw an exception and fail the build with a meaningful error message. I try to avoid afterEvaluate at all costs but i find it's generally fine for validation but it should never be used for configuration.
m
That's fair. It's only two projects so far using it so I guess it's not too bad
a
What have you done will work perfectly and it's absolutely fine! Just trying to share some of the things I've ran into and regretted when trying to write convention plugins of my own. Just to be clear as well, I'm not saying the convention plugin is a bad idea. It's an amazing one! Just questioning the idea of hiding gradlePlugin with myPublishing
๐Ÿ‘ 1
m
"Fun" fact with the method solution to make lazy stuff: If you reference anything else in that file the extension class (
PublishingOption
above) captures the current context and becomes an inner class so you have to pass "this" when creating it:
Copy code
val extension = extensions.create("myPublishing", PublishingOptions::class, this)
I think I'm just going to drop the
kotlin-dsl
plugin. That's a lot of trouble and extra compilation time to get a little bit of typesafe accessors
t
tip: move your
PublishingOptions
class into its own
.kt
file. Not only will it be a true top-level class so you don't need that
this
argument, you can also control its actual name which makes it much easier to
import
from other projects (other plugins building on top of yours, or just projects that want to factor some things with helper methods or whatever)
โž• 1
๐Ÿ‘ 1
m
Makes sense ๐Ÿ‘
I'll still move everything to
.kt
I think :)
A tiny bit more verbose but less surprises and less generation of typesafe accessor
c
I usually only the plugin itself in the .kts, and la the classes I use (Extension, tasks, รบtils) in .kt I think the biggest advantage is that my customers or collaborators will understand it better when I don't need the plugin boilerplate, and I use the same DSL they are used to
๐Ÿ‘ 1
m
I ended up with this for my
build-logic/build.gradle.kts
Copy code
plugins {
  `embedded-kotlin`
}

apply(plugin = "kotlin-sam-with-receiver")
extensions.findByType(SamWithReceiverExtension::class.java)
          .annotation(HasImplicitReceiver::class.java.name)
I'm pretty happy with it, it has a good chunk of the "DSL" parts so that copy pasting "mostly" works (except for top level extensions and configurations) And it's close enough to "regularโ€œ Kotlin that I don't feel there's too much magic going on. Also allows me to use Kotlin 1.5 and saves "some" accessor generation so I'm hoping it's a bit faster
But it's mostly myself on the project so yea if more people contribute, that might create some questions as to why the top level extensions do not work