Could not find implementation class for plugin error when using Gradle 4.1+

Hello,

I’m trying to develop a gradle plugin and running into some issues. This is my first attempt at developing a gradle plugin and I’m still learning following Gradle’s user guides. I seem to be having some problem depending on what version of Gradle I use. I’m hoping you can help me with this and tell me if I’m doing something wrong or if there’s a bug on latest/newer versions of Gradle.

First, I have my plugin source like this:
File path: gradle-plugin\src\main\groovy\com\my\org\gradle\mytool\plugins
File content:

package com.my.org.gradle.mytool.plugins

import org.gradle.api.Plugin
import org.gradle.api.Project

class  HelloPlugin implements Plugin<Project> {
    Project project
    
    void apply(Project project) {
       project.task('demo') << {
            println "hi!"
        } 
    }
}

I then added a plugin id through the resource file named "my-plugin.properties"
File path: gradle-plugin\src\main\resources\META-INF\gradle-plugins
File content:
implementation-class=com.my.org.gradle.mytool.plugins.HelloPlugin
I then added a unit test for this plugin using Spock
File path: gradle-plugin\src\test\groovy\com\my\org\gradle\mytool\MyPluginSpec.groovy
File content:

package com.my.org.gradle.mytool.tests

import spock.lang.*

import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.junit.Rule
import org.junit.rules.TemporaryFolder

import static org.gradle.testkit.runner.TaskOutcome.*

class MyPluginSpec extends Specification {

    @Rule
	final TemporaryFolder testProjectDir = new TemporaryFolder()
    
    
    def "test the demo task" () {
        given:
            //copy some files from "gradle-plugin/test-resource" directory that contains a build.gradle file and applies the plugin as "apply plugin: 'my-plugin'"
        when:
            Run a gradle build using Gradle testkit
        then:
            //capture the output of the build and validate that the demo task worked.
    }
}

My main build.gradle file for building this project looks like this:

apply plugin: 'java-gradle-plugin'
apply plugin: 'groovy'

dependencies {
    compile gradleApi()
    compile 'org.codehaus.groovy:groovy-all:2.4.4'
    compile 'org.gitlab4j:gitlab4j-api:4.6.0'
    
    testCompile gradleTestKit()

    testCompile('org.spockframework:spock-core:1.1-groovy-2.4') {
        exclude module: 'groovy-all'
    }
    testCompile 'org.codehaus.groovy:groovy-all:2.4.4'
    
    testRuntime ('com.athaydes:spock-reports:1.2.7') {
        exclude module: 'groovy-all'
    }
}

If I run the build using Gradle 2.11 version, compilation and the unit test is successful. If I use Gradle 4.1 or 4.2, I need to update my main build.gradle script so that it uses Groovy 2.4.11; otherwise I get errors about wrong groovy being loaded. So, I update it like this:

apply plugin: 'java-gradle-plugin'
apply plugin: 'groovy'

dependencies {
    compile gradleApi()
    compile 'org.codehaus.groovy:groovy-all:2.4.11'
    compile 'org.gitlab4j:gitlab4j-api:4.6.0'
    
    testCompile gradleTestKit()

    testCompile('org.spockframework:spock-core:1.1-groovy-2.4') {
        exclude module: 'groovy-all'
    }
    testCompile 'org.codehaus.groovy:groovy-all:2.4.11'
    
    testRuntime ('com.athaydes:spock-reports:1.2.7') {
        exclude module: 'groovy-all'
    }
}

Now, when I run the build using Gradle 4.1 or 4.2, I get an error with following message about the plugin implementation class is not able to load the class that it’s referring to.


    * What went wrong:
    A problem occurred evaluating root project 'junit7340673529257668127'.
    > Could not find implementation class 'com.my.org.gradle.mytool.plugins.HelloPlugin' for plugin 'my-plugin' specified in file:/Users/projects/gradle-plugin/build/resources/main/META-INF/gradle-plugins/my-plugin.properties.

Found out the root cause. In the unit test when I use the testkit to execute a gradle build in an external process, I had the following directories being added in the classpath:

def classDir = [
			new File('bin').absolutePath,
			new File('build/classes/main').absolutePath,
			new File('build/resources/main').absolutePath
		]

I needed to add new File('build/classes/groovy/main').absolutePath to that list. After this, using Gradle 4.1 when I run the build, the unit test no longer throws class not found exception.

To inject the plugin classpath you should use GradleRunner.withPluginClasspath(). For a more detailed discussion please see the “Testing Gradle plugin” guide.

Thanks for your suggestion. I’m trying to follow the entire guide and all of the recommendations as part of this development exercise. I haven’t been able to get the withPluginClasspath() working yet, but I’m going to get back to it again.