Gradle : init.gradle is repeat executing common task defined in allprojects block in multi-module projects

I have multi-module project

water (root project)

(sub projects)
-> bluewhale
-> shark

When ‘gradlew clean hello’ is executed, below in the output with print statement from init.gradle.

> Task :clean UP-TO-DATE
task.project.name-->water
task.project.name-->clean
task.project.name-->water
task.project.name-->clean
task.project.name-->water
task.project.name-->clean

> Task :bluewhale:clean UP-TO-DATE
task.project.name-->bluewhale
task.project.name-->clean
task.project.name-->bluewhale
task.project.name-->clean
task.project.name-->bluewhale
task.project.name-->clean

> Task :shark:clean UP-TO-DATE
task.project.name-->shark
task.project.name-->clean
task.project.name-->shark
task.project.name-->clean
task.project.name-->shark
task.project.name-->clean

> Task :hello
task.project.name-->water
task.project.name-->hello
task.project.name-->water
task.project.name-->hello
task.project.name-->water
task.project.name-->hello
I'm water

> Task :bluewhale:hello
task.project.name-->bluewhale
task.project.name-->hello
task.project.name-->bluewhale
task.project.name-->hello
task.project.name-->bluewhale
task.project.name-->hello
I'm bluewhale

> Task :shark:hello
task.project.name-->shark
task.project.name-->hello
task.project.name-->shark
task.project.name-->hello
task.project.name-->shark
task.project.name-->hello
I'm shark

init.gradle

allprojects {
   
 gradle.addListener(new TaskExecutionListener() {
    //The listener is notified of events which occur during the execution of the build.

            void beforeExecute(Task task) {
                 println("task.project.name-->"+task.project.name)
                 println("task.project.name-->"+task.name)
            }

            void afterExecute(Task task, TaskState state) {
             }

}

With multi-module projects, I am facing this issue of common-task(hello) of all projects getting executed all the time. How to fix this in init.gradle ?
why is common task on all projects getting executing every time, is it because of allprojects block in init.gradle, do we have any alternative for this ? Please suggest.

I am looking to print some message on each task pre activity, once the task is successfully executed, print message on post activity through init.gradle.

Hi @carlo_lf @Chris_Dore,

I see you have answered questions related to init.gradle. Can you please suggest here.

Sorry, I am out. Since 2018 I am not working professionally anymore, got retired. :grinning:

The listeners being added via Gradle.addListener are global to the entire build, they are not per-project. Since the addListener call is wrapped in allprojects {} a global listener is being added 3 times (once for each project).

This init script will execute your listener once per task:

gradle.addListener(new TaskExecutionListener() {
    //The listener is notified of events which occur during the execution of the build.
    void beforeExecute(Task task) {
        println("task.project.name-->"+task.project.name)
        println("task.project.name-->"+task.name)
    }
    void afterExecute(Task task, TaskState state) {
    }
})

@Chris_Dore,

Sorry I forgot to include project.group and few lines in my initial init.gradle code. adding it now.

I am trying to access group, name and version and few more values from project outside the addlistener, I am using allprojects wrapper to access project.

allprojects {

def groupId = project.group
def artifactId = project.name
def version = project.version

Upload uploadTask = project.getTasks().withType(Upload.class).findByName("uploadArchives");

gradle.addListener(new TaskExecutionListener() {
    //The listener is notified of events which occur during the execution of the build.
    void beforeExecute(Task task) {
        println("task.project.name-->"+task.project.name)
        println("task.project.name-->"+task.name)
    }
    void afterExecute(Task task, TaskState state) {
    }
})
}

How can I access project without wrapping it up with allprojects ? I need group, name and version of all the projects.

Your project specific code can remain in allprojects while your build listener is moved out:

allprojects {
    def groupId = project.group
    ...
}
gradle.addListener(...)

@Chris_Dore

I have tired this solution already. Below is the task execution output of ‘./gradlew clean hello’. If you look that the value of the project.name, last submodule project.name is picked always. ‘shark’ is the last project evaluated.

> Task :clean UP-TO-DATE
beforeExecute task.project.name-->water
beforeExecute task.name-->clean
groupId -->water
name -->shark
version -->unspecified
afterExecute task.project.name-->water
afterExecute task.name-->clean

> Task :bluewhale:clean UP-TO-DATE
beforeExecute task.project.name-->bluewhale
beforeExecute task.name-->clean
groupId -->water
name -->shark
version -->unspecified
afterExecute task.project.name-->bluewhale
afterExecute task.name-->clean

> Task :shark:clean UP-TO-DATE
beforeExecute task.project.name-->shark
beforeExecute task.name-->clean
groupId -->water
name -->shark
version -->unspecified
afterExecute task.project.name-->shark
afterExecute task.name-->clean

> Task :hello
beforeExecute task.project.name-->water
beforeExecute task.name-->hello
groupId -->water
name -->shark
version -->unspecified
I'm water
afterExecute task.project.name-->water
afterExecute task.name-->hello

> Task :bluewhale:hello
beforeExecute task.project.name-->bluewhale
beforeExecute task.name-->hello
groupId -->water
name -->shark
version -->unspecified
I'm bluewhale
afterExecute task.project.name-->bluewhale
afterExecute task.name-->hello

> Task :shark:hello
beforeExecute task.project.name-->shark
beforeExecute task.name-->hello
groupId -->water
name -->shark
version -->unspecified
I'm shark
afterExecute task.project.name-->shark
afterExecute task.name-->hello

init.gradle

def groupId = ""
def artifactId = ""
def version = ""

allprojects {

groupId = project.group
artifactId = project.name
version = project.version

Upload uploadTask = project.getTasks().withType(Upload.class).findByName("uploadArchives");
}
gradle.addListener(new TaskExecutionListener() {
    //The listener is notified of events which occur during the execution of the build.
    void beforeExecute(Task task) {
        println("beforeExecute task.project.name-->"+task.project.name)
        println("beforeExecute task.name-->"+task.name)
        println("groupId -->"+groupId)
        println("name -->"+artifactId)
        println("version -->"+version)
    }
    void afterExecute(Task task, TaskState state) {
         println("afterExecute task.project.name-->"+task.project.name)
         println("afterExecute task.name-->"+task.name)
    }
})

group, name and version values are overridden on each module evaluation. As those variables are global.

@Chris_Dore I have corrected the init.gradle code snippet in my previous comment as per my local init.gradle script.

@Chris_Dore, Do we have any other way of accessing project inside gradle.addlistener ?

I need GAV values for few tasks in beforeExecute and afterExecute methods…
For Ex:
When Gradle is executing uploadArchives or publish task, I need to do some pre and post validations having GAV details as inputs.

Thoughts;

  1. Can you use Task.doFirst() and Task.doLast() to do what you want?

  2. Your example code is already accessing the task’s associated project via Task.getProject(), that could be used to get the project values you seek.

  3. If you want/need to use a TaskExecutionListener, “inject” the values into your TEL implementation, something like:

     class MyValidatingTEL implements TaskExecutionListener {
         Task t // or maybe a list of tasks if you don't need a listener for every task
         String group
         ...
         MyValidatingTEL( Task t, String group, ... ) {
             this.t = t
             this.group = group
         }
         void beforeExecute( Task task ) { if( task.equals( t ) ) { ... } }
         ...
     }
    
     Upload uploadTask = ...
     gradle.addListener( new MyValidatingTEL( uploadTask, project.group, ... ) )

Keep in mind that the publication tasks created by the maven-publish plugin do not necessarily have the same group, artifact, and version values as the project. A maven publication defaults to the project values, but they can be overridden in the publication’s configuration. I don’t have experience with uploadArchives, so I can’t comment on that.

@Chris_Dore I am also checking project values on publication config if it is overridden.

Let me check on your points and get back to you in sometime if I could achieve the desired outcome. I appreciate your efforts on this… thank you.

@Chris_Dore,

2nd point, worked for me. thank you for sharing your thoughts.