This message was deleted.
# plugin-development
s
This message was deleted.
t
I believe something similar has been discussed a few weeks ago. The outcome of the discussion was, IIRC, to use methods in your extension rather than properties, to make it clear that it's "imperative" (think about `useJUnit()`/`useTestNG()` of the
Test
task, not identical but it makes it clearer that it will reset/clear some configuration and not just change a property value)
v
Actually
afterEvaluate
would not be too late to add dependencies or apply plugins. But everytime you use
afterEvaluate
you create new race conditions as you then depend on ordering and for example don't see changes done in
afterEvaluate
blocks done after your
afterEvaluate
block. And as Thomas correctly said, imho using a method in the extension is the best way, as there is not way to react to properties being set currently. You can either have a method like
useSetupX()
or also with parameters that then does what you need, or you can have something like a
doThings(Action<SubExtension>)
so that you then can have
Copy code
myExtension {
    doThings {
        subExtensionsPropertyA.set(1)
        subExtensionsPropertyB.set(1)
    }
}
and then in the
doThings
before executing the action you could check it was not already configured and after executing the action you can derive your logic from it. Whichever way you prefer.
j
Thank you for the help. So if I wanted to have some default configuration, do you think that would also make sense to be a method? Or I suppose if I call a method I could potentially remove a dependency. And I definitely agree that I would prefer to avoid afterEvaluate as much as possible.
To give a more concrete example, I was mostly thinking that maybe the default would be useJUnit() for example, but if the user called useTestNG() I would have to remove the junit deps and then add the test ng deps, right?
v
I'm not sure whether removing dependencies works or is a good idea. Maybe in that case you need something like
beforeResolve
where you add the default dependencies if nothing was configured in the extension. Or maybe even better you create a new (possibly hidden) configuration where you define default dependencies to be the default ones and if the method is called add non-default dependencies, this way the defaults are only used if no were set explicitly.
j
Ahh I didn’t know about
beforeResolve
. I suppose that happens post configuration but before tasks are evaluated.
v
It happens before the respective configuration is resolved. That can be before some tasks are executed but after others are executed because not all tasks need the configurations.
j
Have you considered using different/multiple convention plugins instead of an extension? For example: Option 1: Give several alternatives (one for each combination of things that makes sense in your project)
Copy code
plugins {
  id("my-java-project-with-junit")
}
Or
Copy code
plugins {
  id("my-java-project-with-testng")
}
Option 2: Let the users “stack” convention plugins
Copy code
plugins {
  id("my-java-project") // JUnit is the default here
}
Or
Copy code
plugins {
  id("my-java-project")
  id("my-extra-testng") // Switches to things TestNG
}
I recently strictly use Option 1 several projects which gives you all the control in the plugins and makes it easy to use/understand for the developers as you have a limited set of predefined combinations. If the number of combinations explodes, Option 2 might be better though. If you feel that you need extensions, I would also do what was proposed above - offer methods on the extensions - like your own
myExtension.useTestNG()
which then directly modifies the declared dependencies (and whatever else you want to configure).
j
Thanks for commenting. I didn’t consider stacking convention plugins like that. If I used option 2, how would I know to apply the junit dependencies for example? I suppose I would be monitoring the plugins as they are added and if I see the TestNG plugin show up I would remove a beforeResolve listener on the configuration I’d be using to add the junit dependencies? Or is there an even easier way Im missing
v
The one I said but you ignored? Make a new configuration, add junit as default dependencies, when testng is applied add testng as actual dependencies and make
testImplementation
or whatever you would have added them otherwise extend your new configuration.
j
I think there are several options. Using an additional configuration is an option or modifying the dependencies of
testImplementation
directly is another one. I think in this case I would probably add the junit dependency directly to
testImplementation
in the
my-java-project
. And then in the the
my-extra-testng
I would replace/remove the junit dependency again. I would also make
my-extra-testng
apply
my-java-project
in its plugins block so the order is always clear.
j
@Vampire Sorry if I offended you. I didn’t mean to ignore any suggestions you have made. The question was more towards @Jendrik Johannes but I think we are thinking on the same wave length. Thank you all again for your help and insight on this.
v
No offense happened, don't worry 🙂
j
https://melix.github.io/blog/2022/03/gradle-conditional-dependencies.html this actually seems relevant to my discussion for any future readers that come across this thread.
❤️ 1