This message was deleted.
# community-support
s
This message was deleted.
e
check out junit, a gradle maintainer (@Marc Philipp) is contributing there. 🙂
v
Which still doesn't mean it is fully idiomatic. 😄
But https://github.com/jjohannes/idiomatic-gradle/ should probably be a good reference even with @Jendrik Johannes not being a Gradle employee anymore. 🙂
m
Micronaut is close to that. There's still some use of `allprojects`/`subprojects` for edge cases (aggregation) which are not yet greatly supported by Gradle.
See for example: https://github.com/micronaut-projects/micronaut-aot/ One module which uses convention plugins, as well as shared plugins (for other Micronaut projects)
j
Spring Boot (with the convention plugins written in Java): https://github.com/spring-projects/spring-boot/tree/main/buildSrc
Ah you checked Spring Boot… I would say it is pretty idiomatic last time I checked. Only that it does not use the Gradle DSLs for the convention plugins, which is maybe the thing that makes it not a good candidate for your case (?)
t
Thanks for the suggestions! I'm not totally sure what you mean by idiomatic. Can I substitute best practice instead? 🤔 FYI Spring Boot uses allprojects here and junit5 does similar. micronaut-aot could be a good candidate, but I'm unsure why it's not using buildSrc.
Gradle itself
Nice!
v
Because an included build is better in most regards and can basically do the same things with just slight differences. 🙂
🙏 1
m
there are many more Micronaut projects than AOT following those practices. It's a large multi-repo project which needs coordination and convention plugins, so most projects are already following best practices. There are still some changes to be made, but it uses version catalogs, convention plugins, settings plugins, custom component types (BOMs+catalog publishing) etc.
👍 1
Many Micronaut projects still use
buildSrc
though.
For me the biggest problem to solve, which I also had when migrating the Groovy build to best practices, is aggregating projects. It's extremely cumbersome.
t
Because an included build is better in most regards
So
includeBuild
is the unofficial replacement for buildSrc if performance is important? Are there any plans to fix the cache invalidation problem in buildSrc?
v
Last I heard was, that at some point
buildSrc
should become a normal included build. But I don't know whether that's still the plan or when that would finally happen. But I actually anyway prefer to have the build logic more separated and have it for example in
gradle/build-logic
.
m
Could you please clarify a bit, what you mean by aggregation?
j
I think with aggregation, Cédric was referring to combining artifacts from different projects into something new – like packaging the application or creating a test coverage report that covers all (sub)projects. This is something you typically need to do towards the “end” of the build process. Gradle introduced new paradigms/best practices for this with “variant aware dependency management”. Which works very well for things that come with Gradle core (like the Java runtimeClasspath) or are provided by plugins like the Android Gradle Plugin. But if you want to do something custom, the APIs/DSL are cumbersome to use in certain places and you need to know which parts to use and which to avoid. This is my ~10min attempt to give an overview:

https://www.youtube.com/watch?v=2gPJD0mAres&list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE

❤️ 1
m
Not only that. I'm also referring to automating dependencies to projects of a certain kind. For example a platform should contain dependencies on all libraries defined in the project.
e
Hi, is there a reference where I can read about this cache invalidation problem? What exactly causing it? And why included build is not affected? Thanks.
v
buildSrc
is always run before the main build and added to the class path of each and every build script of the main build. So if anything in
buildSrc
changes, the class path of all build scripts changes. With an included build this is different. Only what is used built and added to the class path of the build script where it is used.
e
Hi @Vampire thanks for answering, I have some follow up questions regarding this Is this only applied to Gradle script inside the included build? My understanding is the build will always be invalidated if build dependencies are changed. I also use included build for our internal plugins, and even when I do non-ABI change in the plugin, it will invalidate the main build with reason of classpath change
Copy code
The task was not up-to-date because of the following reasons:	
Class path of task ':utils:compileDebugKotlin' has changed from dd4a749a8903049c26808dde8113cf04 to 078f07687a37110a2757655aa16bc6df.
v
I don't know what you mean by "Is this only applied to Gradle script inside the included build?", but I tend to answer with "No" from the used words.
My understanding is the build will always be invalidated if build dependencies are changed.
"the build" is too general spoken. If you have a main build with project
root
and subprojects
A
and
B
. If you have
buildSrc
it is prefixed to the classpath of all those projects build scripts and thus any change changes all their classpaths. If you have a plugin in a project in an included build that is used only in
A
, then it will only change the classpath of
A
.
e
Ahh now I got your point. In my case though, I have one included build that contains multiple plugins that used in various projects including
root
Do I need to have a multiple included builds to avoid above case?
it is prefixed to the classpath of all those
How can I check this?
v
Ahh now I got your point. In my case though, I have one included build that contains multiple plugins that used in various projects including
root
As the root projects class loader is parent of the subproject class loaders, I guess it is the same for the class path. So anyhting you use in the root project probably has the same effect of changing all class paths, but I'm not 100 % sure about that.
Do I need to have a multiple included builds to avoid above case?
Also not 100 % sure, but I think different projects in the included build should already be sufficient.
> it is prefixed to the classpath of all those
How can I check this?
Check what?
e
Check what?
The classpath for each project Anyway, thanks for all the answers, it's really helpful. I will try to verify all the points above 👌 Also It seems I need to revisit all about classpath and classloader 😆
v
Yeah, class path and class loader topics in Gradle are partly a bit complex and unintuitive. 😞
🙂 1
The classpath for each project
When it is about things coming from a repository or included build, the
buildEnvironment
task should give you information. A build scan probably too. Things that are coming in through
buildSrc
are not included as far as I remember as
buildSrc
is special as always. And as a last resort, set a breakpoint and inspect the class loading hierarchy.
You have also quirks like project
A
and script plugin
X
and
Y
(not precompiled script plugins, legacy ones). In both,
X
and
Y
, you add plugin
Z
to the class path using the
buildscript
block. In
X
you apply the plugin
Z
which adds a task of type
ZTask
. In
Y
you do
tasks.withType(ZTask).configureEach { ... }
. In
A
you apply both script plugins. But the effect of
Y
will not be there. Because
Z
is in different class loaders in
X
and
Y
, the class
ZTask
in
Y
is a different class than the class
ZTask
in
X
, so the
withType
will not found any match.
e
And as a last resort, set a breakpoint and inspect the class loading hierarchy.
Hi @Vampire, can you give me some pointer on the point above?
v
Not if you don't ask anything as I cannot guess what more info you need. Set a breakpoint and then inspect which class loader a specific class comes from and what the parents of this class loader are and so on.
e
Sorry, I never done the exercise before so I’m not sure where to start 😅 Ah, so set the breakpoint somewhere and the run
Copy code
Class.forName("com.org.myplugin").getClassLoader();
And then get the parent of that class loader and so on?
v
For example. Well,
com.org.myplugin
is not a class, so you will get a CNFE. And you don't actually need
Class.forName
, you can directly use
MyPlugin.class.getClassLoader()
. But basically, yes
👌 1
e
Thanks for the support @Vampire 👍
👌 1