Strange behavior of a clean task

I am working on a new plugin which modifies build flow and noticed very strange behavior of a clean task. I have a test project which includes two sub projects (A and B), each sub project has HelloWorld.java class in it, build file in each subproject is simple:

repositories {
    mavenLocal()
}
apply plugin: 'java'

Root build file is like this:

buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
    }
}

subprojects { sp ->
    sp.afterEvaluate { p->
        p.tasks.each { p.logger.lifecycle('Task: ' + it.name)}
        p.logger.lifecycle('Find task: ' + p.tasks.findByName('clean'))
    }
}

//gradle.projectsEvaluated {
//    subprojects { sp ->
//        sp.tasks.each { sp.logger.lifecycle('Task: ' + it.name)}
//        sp.logger.lifecycle('Find task: ' + sp.tasks.findByName('clean'))
//    }
//}

If I run gradle clean build as is it will print only Find task: task ':A:clean' / Find task: task ':B:clean' but there will be no messages like Task: clean for each sub project. If I comment out subprojects closure and uncomment gradle.projectsEvaluated closure it will print both Task: clean and Find task: task ':A:clean' / Find task: task ':B:clean'
Thus, when project is evaluated, task clean exists somewhere in task container, but iterating over each task does not return it. It starts to appear only after all projects are evaluated.
Could you please explain why?

Gradle 4.6
MacOS Sierra
JSDK 1.8

1 Like