For Gradle 7.4, is there a replacement for "TaskEx...
# general
k
For Gradle 7.4, is there a replacement for "TaskExecutionGraphInternal.addEntryTasks()" or better yet, a way to add a task after it's dependencies have been configured but before the graph is computed? We were using it like this:
Copy code
fun Project.addTaskToTaskGraph(taskProvider: TaskProvider<*>) =
        afterEvaluate {
            // A hack to delay adding the task until its dependencies have been configured, but before the graph is
            // computed.
            (gradle.taskGraph as TaskExecutionGraphInternal).addEntryTasks(listOf(taskProvider.get()))
        }
v
The question is probably more why you want to do that. What is the use-case, what do you want to achieve, why do you need that?
k
This is to allow reconfiguring some of the tasks and optionally disabling some of them. We use it in sort of a "bootstrap".
v
Still sounds not quite right what you try. Also using something called
...Internal
is a very strong sign of code-smell. 🙂 If you want to configure tasks, why don't you just do it? And if you want to disable tasks after things ar configured, use
Task.onlyIf
closure which is evaluated at task execution time to check whether the task should run or not.
k
yeah..definitely code smell to me as well but 🤷 It's basically making this bootstrap task a pre-requirement for any tasks that are run. I.e. any gradle command line command you run, this task should be first. I don't think Task.onlyIf does this...
v
tasks.configureEach { dependsOn(mybootstrapTask) }
c
hey! I wrote this code originally – I was aware that using internal classes is not supported, but this was the only way I could find to force the execution of a task without breaking the configuration cache. Before that, we’d just add the desired task to
StartParameter
but I don’t think that’s any better.
here’s the motivation: we want to force a bootstrap task to run in the root project in every build, whether it’s started in the IDE or in the command line
unfortunately, we don’t run any other tasks in the root project, so your suggestion won’t work
v
tasks.configureEach { dependsOn(rootProject.mybootstrapTask) }
?
c
that’s adding this reference to thousands of tasks, while crossing project boundaries
which may work, but it strikes me as undesirable in other ways
v
I guess for that edge use-case crossing project boundary is ok
Adding the reference to many tasks should not be a problem, and expresses exactly what you want. Before any task is run, this task needs to be run.
And definitely better than using an internal class I'd say 😄
c
that’s not what we want though. We just want the task to run in parallel with the build
that would block the execution of every tasks until bootstrap is complete
v
Hmm, what does the task do?
c
it deploys changes to the development environment
which we want to happen automatically for all developers behind the scenes
v
How about maybe doing it in a build service?
c
it’s an unconventional use of the Gradle build, but I found it to be surprisingly frequent, with a bunch of other companies using a similar hack
(@Zac Sweers did you happen to use something like this?)
it’s a task though: it’s copying files, fetching dependencies, breaking the work into dependent subtasks, delegating work to workers
v
Hm, I'm out of simple ideas right now. Actually it sounds to me like you simply shouldn't do it, but have it as manual action the developer can invoke. I was about to suggest to use a custom gradle wrapper start script where the bootstrap task is hard-coded so it is always specified, but that of course only works from command line of course, not from IDE. If IntelliJ is your IDE, you could also configure some task to always run after sync or at other defined points using the
idea-ext
plugin. Another possibility for corporate projects would of course be a custom distribution. There you can basically change any Gradle implementation detail you like, including the possibility to inject such a bootstrap task.
c
yeah, we considered all that. None of them is ideal: • We’re supporting 100+ developers. Relying on all of them individually to run updates on a regular bases doesn’t work. Automatic deployment guarantees consistency of all development environments, with timely deployments and minimal maintenance cost. • Running as a background build through some other mean is disruptive, since we can’t run Gradle builds in the background without interfering the developer’s ability to run a build. We can attach it to hooks here and there, but we’ve found that running transparently during the build just works. • A custom distribution is a huge pain to maintain – especially if it’s just to implement something that belongs in the build configuration anyway.
Is it conceptually wrong however? Is programmatic access to the execution plan during configuration time something Gradle would consider?
v
Well, one death you have to die. 😄 You can also open a feature request to Gradle for supporting such a use-case. I'm just not sure how much priority it will get. 🙂
I don't know what the Gradle guys would consider, I'm just a user like you
c
yeah, I should’ve done that originally 😬. Let me try…
v
But to me it sounds a bit like out-of-scope of what Gradle is for. But that's just my personal feeling. 🙂
c
yeah, I understand