For Isolated Projects (which we are far, far away ...
# plugin-development
c
For Isolated Projects (which we are far, far away from using, but I’m trying to write new plugin code “correctly”) - is the idea that since you can’t access the extensions/properties/other state of other projects, every exchange of information between two project should happen through resolving a
Configuration
with custom attributes a la https://docs.gradle.org/current/userguide/cross_project_publications.html#sec:variant-aware-sharing? Or is there some other way to safely read data from other projects?
a
a BuildService can work, but can be delicate https://docs.gradle.org/8.13/userguide/build_services.html
m
You can read
Project.name
but that's about it 😅
😂 2
c
mm, I think with the build services feels like there may be timing issues? ie a project gets evaluated after another, doesn’t register the right info in time?
1
I guess if you did everything really lazily it may work?
m
build services always get me a bit itchy too but I have never really investigated much deeper given that the
Configuration
dance usually works for my use cases
a
I think with the build services feels like there may be timing issues
It depends on what data you want to share. It will be fine if the BuildService just collects data using the Provider API, and the data is only computed during task execution.
the problem with BuildServices is they mandate the buildscript classpath is identical for all buildscripts. If one subproject has a different buildscript classpath then the BuildService can't be accessed consistently :(
c
mmm, I’m currently trying to build something where project A needs to use some information in projects that are dependents of project A (ie the other projects that depend on A). I was trying to do something crazy with lazily computed attributes, but a build service with a lazy map (with project paths a keys) might work too, provided all projects are actually evaluated
m
the problem with BuildServices is they mandate the buildscript classpath is identical for all buildscripts.
Good old https://github.com/gradle/gradle/issues/17559
🚀 1
c
re: the buildscripts, we enforce they’re all the same anyway, it’s such horrible errors/debugging when they’re different
👆 1
I have had enough classloader pain in my life already
🫂 3
1
e
it's not that all projects need to have the same buildscript classpath necessarily, but the buildservice must be in a shared parent. I dont' see how you'd run into issues if you register it in a root or settings plugin
👆 2
it sounds like you're trying to do something backwards though… I don't think you can rely on your dependents all being loaded
m
I’m currently trying to build something where project A needs to use some information in projects that are dependents of project A (ie the other projects that depend on A)
I've given up on having a "smart" way to do this, I force my users to declare the two way dependency
It's a pain because it's error prone (it's easy to forget a backlink) but it's the only reliable PI compatible way I found
c
yeah, I’m aware this might not make sense;
I’ve given up on having a “smart” way to do this, I force my users to declare the two way dependency
Ideally they would, unfortunately there are ~4000 repos and 1000 users to deal with, so need to do something automatically
😅 1
m
I'm curious if you find something. To my last understanding, this was just not possible
Maybe BuildService is the way indeed 🤔
c
I’ll keep you updated. I think I might be able to do it, but it feels if a project is ever not evaluated (eg Configuration-on-demand, which seems like Isolated Projects will eventually make “safe” - our monorepo owners crave it) might cause issues
m
Yea, exactly, feels like BuildService can't force task dependencies...
c
nice, this is my exact problem
p
I don’t know if it is a correct api, but there is a new Flow api: FlowAction etc., but there is no real documentation and the jacadocs are not real helpful (only about playing a song…). But I never used this api.
👀 1
p
Yeah, and there is only 1 event, the end of build event 🤷🏻‍♂️ very strange
m
TIL another API in Gradle
They make it sound like it's for listening to build events
(no pun intended 😄)
p
But I usually also use all the configuration pain and plain old files to pass data. On the other hand, this will also work out of the box with published artifacts, so refactoring a (mono) repo is possible.
plus1 1
m
True, it's a forcing function of making it work with external dependencies
c
we use FlowActions extensively for doing an action at the end of build (basically replacing the build finished listener that is deprecated) - I’m not sure it has more real uses beyond replacing the old build listener api?
a
We plan to introduce more Isolated Projects-safe APIs to share data across projects. It’s still in the early design phase and not in focus at the moment, but it’s something we definitely want to improve. Umbrella issue: https://github.com/gradle/gradle/issues/25179
👀 1
🙌 1
I filed https://github.com/gradle/gradle/issues/29037 at the time
@Martin, the issue describes a mechanism that you’d like to have, but only touches on the actual use cases. Do you have anything else in mind, rather than aggregation of things from (subset) of subprojects in a parent / root project? In other words, would the aggregation use-case cover your needs? (https://github.com/gradle/gradle/issues/29403)
c
I do notice that it’s possible to enumerate other projects and declare a dependency (with appropriate attributes) on each, but I don’t notice an easy way to filter to just projects that create the given artifact. We can set
isLenient(true)
this is basically what I’m trying - if there was a built in way to do this, it would be great
a
Unfortunately, it’s the only IP-safe way for now.
m
> In other words, would the aggregation use-case cover your needs? @Alex Semin I feel like looking at it from the aggregation point of view is very limiting. Aggregation is a particular case of a more general problem
Talking BCV + publishing examples, aggregating accross all projects feels bad, what I want is individual project to register themselves to the "root" project: not all sub-projects want to publish or track their API
My other use case is multi-project codegen in Apollo. It needs a circular dependency between projects (not between tasks) and it's very easy to forget one. Would be kind of handy to lift this automatically
a
Talking BCV + publishing examples, aggregating accross all projects feels bad, what I want is individual project to register themselves to the “root” project: not all sub-projects want to publish or track their API
What is BCV? What are you trying to achieve by letting individual projects register themselves in the root?
m
Binary Compatibility Validator
Generally trying to express the dependencies between projects. Why scan all projects if we know only some of them will publish
Of course the coupling had to be loose. If the root project doesn't know what to do with a subproject registering itself, I'm fine with a failure and/or no aggregation being run
p
But how do you know what project will publish without configuring them?
m
Good point.
I'm guessing the full project graph would need to be computed once at least
a
That is correct
p
Yeah, and for this reason you could use lenient=true
m
But this should be fine. "Just" make it easy to cache and reuse the project graph
What is fundamentally different from tasks?
If a project didn't change, just do not run its build script again
p
Isn’t project graph = configuration cache?
m
The CC stores the task graph iiuc
But the relationship between projects could also be cached I guess. Of course none of that is easy but feels like it should be the end goal
isLenient
feels the wrong tool