Can we define more than a single Plugin class in a Gradle buildSrc


(John Verne) #1

[This was cross-posted from StackOverflow. Sorry about that, but I realized afterwards that this might be a more appropriate place for this question. If I get a solution or explanation at either location I’ll circle back to both with those results.]

I have a pretty typical Gradle library project that contains a collection of modules (either Android or pure Java) that depend on some common configuration.

This common configuration is abstracted into a “publishConfig.gradle” file (which is read in via apply in those build.gradle files that need it) and some custom Tasks captured in a buildSrc. This question is about the latter.

The buildSrc is a single module/project consisting of source (as Groovy) in a specific package as a single Groovy file with two classes: the class that implements Plugin and the plugin extension class. e.g.:

org.clvrmnky.gradle.plugins.LibraryPlugin

This configuration and the defined Tasks work without error. No problem there.

Now I want to add additional custom tasks for a different reason (remember, this is all part of a shared custom configuration for a growing number of submodules to the root project) so I added a parallel class file that defines a new plugin class implementing Plugin. e.g.:

org.clvrmnky.gradle.plugins.BuildBreaker

For reference, here is the class and task definition snippet:

[...]
public class BuildBreaker implements Plugin<Project> {
    static def authString = fetchSonarAuthString()

    @Override
    void apply(Project project) {
        project.extensions.create("buildbreaker", BuildBreakerExtension)

        project.task([
            description: 'Fail this task if the Sonarqube Quality Gate does not pass.',
            dependsOn: ["sonarqube"]
        ], 'breakOnBadQualityGate') {
[...]

That is, the class and task methods are defined similarly, but have different String identifiers.

However, when I do this, the new Tasks I define are not visible to the root project or any submodule of the project:

PS C:\rd\SOPLibs\Commons> .\gradlew.bat  breakOnBadQualityGate
:buildSrc:compileJava UP-TO-DATE
:buildSrc:compileGroovy UP-TO-DATE
[...]    
FAILURE: Build failed with an exception.

* What went wrong:
Task 'breakOnBadQualityGate' not found in root project 'Commons'.

* Try:
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option
 to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

The build directory contains classes for all the source, and there is a lib jar that contains these classes which I presume is being supplied to the Gradle classpath at runtime. That is, this is building and packaging without error.

I’ve seen hints that you need to tweak the buildSrc build.gradle on multi-project buildSrc projects so that all the jars are on the classpath at runtime, but in this case we have a single jarfile with multiple Plugin tasks.

I’ve also tried moving the BuildBreaker class to a separate package, but this did not solve the problem.

Can we not implement more than one Plugin class in a single buildSrc, even if they have different classnames? Or do I have to split these out into multiple buildSrc projects?


(John Verne) #2

I am an idiot and didn’t actually tell any of my Gradle scripts to use the plugin. Duh. Classic PEBKAC.

i.e., I needed to specify this somewhere useful:

apply plugin: foo.bar.MyPlugin

You know. Like I did for the other parallel plugin.