Custom plugin: How to find all defined source sets

Hi,

I’m currently trying to write/fix a Gradle plugin which should have the ability to create a custom task for every defined source set but I’m failing to make it work.

Example Gradle build

plugins {
  id('java')
  id('com.example.my-plugin')
}
sourceSets {
  mySourceSet {}
}

With this Gradle build, the plugin should automatically create customTaskForMain and customTaskForTest (from the Java plugin), and customTaskForMySourceSet (custom source set).

Here are the stripped down versions of how I was trying to accomplish creating a custom task for every source set in a Gradle project.

Attempt 1

This doesn’t work because at the time of evaluation the source sets might not have been created yet:

class MyPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        def sourceSets = project.extensions.getByType(SourceSetContainer)
        sourceSets.each {
            project.tasks.register("customTaskFor" + it.name)
        }
    }
}

Attempt 2

This doesn’t work because at the time of evaluation the custom source set might not have been created yet and only tasks for the main and test source sets provided by the Java plugin will be registered.

Additionally this would make supporting multiple plugins a bit cumbersome.

class MyPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.plugins.withType(JavaPlugin) {
            project.extensions.getByType(SourceSetContainer).each {
                project.tasks.register("customTaskFor" + it.name)
            }
        }
    }
}

Attempt 3

This work in the sense that tasks for all source sets are registered but since they are added after the project has been evaluated, they can’t be referenced in the Gradle build:

class MyPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.afterEvaluate {
            project.extensions.getByType(SourceSetContainer).each {
                project.tasks.register("customTaskFor" + it.name)
            }
        }
    }
}

Example how it’s failing:

plugins {
  id('java')
  id('com.example.my-plugin')
}
sourceSets {
  mySourceSet {}
}
check.dependsOn(tasks.named("customTaskForTest"))

Error message from Gradle:

* What went wrong:
A problem occurred evaluating root project 'my-project'.
> Task with name 'customTaskForTest' not found in root project 'my-project'.

I’m a bit lost now how to achieve the desired result: Collecting all source sets of a project in a stage which still allows registering new tasks in the project.

Maybe some more experienced Gradle plugin developers have an idea how to accomplish this and could help?

Best regards,
Jochen

Thanks to @bmuskalla who pointed me to SourceSetContainer#all(Action<T>) which solved the issue. :heart:

class MyPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        def sourceSets = project.extensions.getByType(SourceSetContainer)
        sourceSets.all(new Action<SourceSet>() {
            @Override
            void execute(SourceSet sourceSet) {
                project.tasks.register("customTaskFor" + sourceSet.name)
            }
        })
    }
}
1 Like