:wave: While doing a code-review for someone's gra...
# community-support
b
šŸ‘‹ While doing a code-review for someone's gradle plugin, I just encountered something I hadn't seem before, and want to know whether there's any basis for my suspicion. Basically, the are registering an extension for their plugin, but instead of using it for configuration, they are using it to expose properties that they then wire up as inputs to other tasks. For example:
Copy code
def myExtensionOutput = extensions.getByName("myExtension").outputFilePath

tasks.register("someTask") {
  inputs.file(myExtensionOutput)
}
The reason they do this is because the file at the output path is expected to just be there as a result of a previous task execution. There is no implied dependency on the source task in the graph. My question is, is this wrong? Why? It feels wrong to me but I can't think of any actual problem they'd encounter and I'd like to check my assumptions. (clearly the better solution is to pass the path in as a property/env-var/well-known-file, and that's what I've recommended)
m
Is this one of my plugins? šŸ˜… I think I'm doing this all the time
b
lol no, it's a local one in our build-logic
šŸ˜„ 1
m
the better solution is to pass the path in as a property/env-var/well-known-file
env-var/well-known-file doesn't really work if you want other tasks in your graph to be input to the plugin
šŸ™ 1
Property
works but then going through extensions feels OK?
I like extensions as the main APIs for my plugins because then I can make the tasks implementation details
y
Besides looking legacy-style, it should work fine, because • it pulls it from an extension (for which assumed is that the actual exists) • it correctly sets up the file input. Now if the file did not exist at build-start, it would be bad as there is not direct way to create the first if it is needed by
someTask
. HTH.
šŸ™ 1
b
Usually the way you set this up is by wiring the source task's output file be the inpute file for the consuming task. You should use RegularFileProperty or DirectoryProperty to model this on the task classes. In the plugin that registers everything you register the source task and then using the returned TaskProvider you can do something like sourceTask.flatMap { it.outputFile } and use that to configure the input file. This way, when you call the consuming task, Gradle will automatically execute the source task, without having to define a dependsOn relationship. Extensions are supposed to be the plugin's user facing DSL. You don't want users to have to know the details of task wiring. Instead you just expose what's relevant for them, e.g. the locations of static input files, or the output location of the final task. Does this make sense?
b
Right, that's how it usually works; this case is different because we expect that the task that produces the file to be run in a completely separate gradle invocation (in CI, determining a set of projects that might be affected by a git change) and then propagated out to other build nodes to be consumed. The consumer processes are the ones that are reading the file.
so, separate task graphs
b
Just curious: why do you try to determine which projects are affected by a git change? Usually I would leave that to Gradle's up to date checking and build cache.
b
Probably we're doing something wrong with build caching, but we observe that many more tests are run than necessary for some changes. Leaving that detail aside, I'm still interested in whether it is problematic to rely on extensions as a data source, rather than a sink for plugin configuration.
b
It's hard to tell without seeing the code. But having one build invocation generate files for a second invocation in order to optimize the second build does sound strange to me, unless the build is really enormous or relies heavily und E2E tests that pull in the whole project and therefore need to be executed on every change without tweaking. But most of the time when too much stuff executes it's caused by instable task outputs that have rippling effects downstream. So looking into that is what I would invest my efforts in.
b
Agreed, it's something worth looking at, but we know it's a problem šŸ™‚ Still curious about the extension use.
b
If you can share a more complete example, preferably a minimal project on github, I can say more about that.
b
The full example isn't much bigger than that, honestly; the extension has one string property, a file path. We take that path, make a file out of it, and add that to task inputs. Probably won't have the availability to put a full and minimal example on github, and I appreciate that it makes it hard to evaluate - thanks for your time and expertise. I got twitchy because it's just not how I've seen extensions used before; other folks in the thread seem to think it's fine, so I may just have been overly cautious.
v
Using an extension to expose something from the plugin to the plugin user is fine imho. It is not the most typical usage but nevertheless just fine.
šŸ™ 1