This message was deleted.
# community-support
s
This message was deleted.
m
I feel like
afterEvaluate{}
could have its own documentation page after all this time 😅
1
e
Copy code
class MyKgpPlugin : Plugin<Project> {
  override fun apply(target: Project) {
    val ext = target.extensions.create("myExtension", MyExtension::class.java)
    
    // configure KGP; should this be wrapped in afterEvaluate
  }
}
m
In that case, I think what you needs is
plugins.withId("org.jetbrains.kotlin.jvm"){}
Because you "react" to KGP being applied
e
That is happening in the function that I use to configure KGP (which comes from a separate library)
m
Then looks like you should be good?
The only place I've seen myself in hard-requirement for
afterEvaluate{}
is when other plugins were using
afterEvaluate{}
and I needed to override them somehow
e
The issue is that the extension isn't configured yet at that point (as @Vampire mentioned in the linked comment)
His solution in the other thread wouldn't necessarily work here because I don't want to impose calling a function in the extensions configuration, and I need to handle the case where there is nothing being configured (i.e. all of the default values are fine)
m
Is the issue checking the password?
Copy code
override fun apply(target: Settings) {
    val ext = target.extensions.create("githubPackagesPluginManagementRepo", Extension::class.java)

    val password = ext.password

    if(password == null) {
      require(ext.ejsonSecretsFile.isPresent) {
        "ejsonSecretsFile must be set"
      }
If that's the issue, I'd postpone checking the password until the task execution
(you can check for the password in your
@TaskAction
method)
e
This is a different project, but same underlying issue.
extensions.create
doesn't mean that the configuration block was called, so the values in the extension object aren't set it (and will always be the default from the plugin's perspective)
m
(to save the user a call to a method in the extension)
Not sure how I feel about this. It's not great but also users like the ability to not call anything 🤷
e
I too like the ability to not call anything 😅 But I've been conditioned to not like using
afterEvaluate
Hence the problem
🤝 1
m
Well, now I'm subscribed to this thread too 😅. Sorry I can't help much more. Hopefully someone in this slack will have more insight.
💯 1
v
The user does not need to be aware he calls a method. :-)
Copy code
myExtension {
    configuration {
        a = "b"
    }
}
💯 1
g
I've noticed a pattern that people use to hide extra method calls in the extensions. They just use nested blocks (of course inner block is just a call to the method accepting an
Action
)..
e
What about handling the default case where the user doesn't configure anything?
☝️ 1
g
I configure it in the plugin or method that handles the configuration action before calling action's
execute
. Also you can check the configuration after that call (e.g. for inconsistencies)
e
Couldn't that cause issues if you're expecting to use the data only one time?
m
And in some cases, there no configuration at all.... Like the user just applies the plugin:
Copy code
plugins {
  id("com.example")
}

// no configuration at all but I still want to register tasks based on default values
vs
Copy code
plugins {
  id("com.example")
}

// explicit configuration. Use these values to register tasks
myExtension {
  configuration {
    // some stuff
  }
}
g
It certainly could. If you want to defend against it you'll have to have a state to avoid applying defaults again. But it's still better then afterEvaluate races between plugins imho
👍 1
m
I don't get it. What if there's no
configuration
Action called at all?
g
Well, in my opinion it's better to unconditionally register tasks and enable/disable them based on the configuration. If you have to register multiple template tasks use NDOC in the extension and just register them based on names in the container. If you do (at least internal) wiring with properties/providers you'll already have conventions/defaults whether user called
configuration
or not
m
Sounds sub-optimal to register default tasks always only to disable them when the user calls
configuration
. That's more noise in the
./gradlew tasks --all
output, etc...
e
In my case, I'm not configuring my own tasks, rather I'm configuring extensions from other plugins (e.g. KGP). So I'd have to: 1. Configure KGP using my default extension values when my plugin is applied 2. Configure KGP again if and when my user configures my extension
👌 1
g
@Martin as a user I would prefer to see even disabled task instead of trying to find some obscure configuration that registers it in the afterEvaluate but ymmv @Eli Graber yeah, something like that, and if they still use a lot of getters/setters there's a chance that you'll have to use afterEvaluate if you depend on their values
👍 1
Buut if you depend on the values set in their afterEvaluate you're screwed anyway, had such an experience (with different plugins since I don't interact with AGP but it was still a pain)
e
I don't actually use any values from them, so it should be fine in that regard. I'm mostly worried about a scenario where the other configuration "locks" after being set the first time (KGP doesn't do this, but I remember this happening a few times in the past)
👌 1
Is it "safe" to say that using
afterEvaluate
is OK in cases where you're not reading from anywhere but your own extension?
v
No, it is never safe. Someone or something can set the extensions values in an after evaluate evaluated after your one
e
But wouldn't that happen anyways, even if I didn't use
afterEvaluate
?
Oh are you saying that someone can set the values on my extension in an
afterEvaluate
that is run after mine does? In this specific case I wouldn't be too worried about that, because it is for internal use only. But I guess it could become a concern if this project grew, and someone ended up using the extension improperly.
v
But wouldn't that happen anyways, even if I didn't use afterEvaluate?
Sure, but if you don't use
afterEvaluate
but either evaluate late in execution phase, or reactive like on function call, that will work properly. If you use
afterEvaluate
you depend on order of those calls. You could prevent further configuration after you evaluated the values to prevent sneaky bugs, but best is still to avoid
afterEvaluate
wherever possible
Oh are you saying that someone can set the values on my extension in an afterEvaluate that is run after mine does?
Exactly
In this specific case I wouldn't be too worried about that, because it is for internal use only. But I guess it could become a concern if this project grew, and someone ended up using the extension improperly.
Well, I usually try to do it right right away, so that debts don't cumulate. But sure, if all is internal you might maybe get away with it. :-)
e
You've made me sufficiently nervous, I'm going to try to do it without
afterEvaluate
😅
🤣 2
v
Perfect. :-D