Skip to content

Instantly share code, notes, and snippets.

@johnrengelman
Created April 8, 2015 13:57
Show Gist options
  • Save johnrengelman/9a20697b2246a9bfaca2 to your computer and use it in GitHub Desktop.
Save johnrengelman/9a20697b2246a9bfaca2 to your computer and use it in GitHub Desktop.
Self applying Gradle plugin project
//place this content in your buildSrc/build.gradle file
//Then apply your plugin to its own build in build.gradle
import org.codehaus.groovy.control.CompilerConfiguration
apply plugin: 'groovy'
repositories {
jcenter()
}
// IntelliJ doesn't let you set the source path for a module outside of its directory.
// This logic basically only performs this configuration when not being resolved in IntelliJ
if (!project.plugins.collect { it.class.name}.any { it.endsWith('JetGradlePlugin')}) {
//Set the source directories for buildSrc to contain the source from the main project
sourceSets {
main {
java.srcDirs = ['src/main/java', '../src/main/java']
groovy.srcDirs = ['src/main/groovy', '../src/main/groovy']
resources.srcDirs = ['src/main/resources', '../src/main/resources']
}
}
}
// Prepare to have your mind blown
// This section evaluates the `build.gradle` from the root diretory and
// then grabs the dependencies block from it and evaluates it on this project.
// So in effect, we are building the main project with itself.
// BOOM
ScriptHolder holder = new ScriptHolder()
CompilerConfiguration cc = new CompilerConfiguration()
cc.setScriptBaseClass(DelegatingScript.class.name)
GroovyShell sh = new GroovyShell(Project.class.classLoader, new Binding(), cc)
//The build file for the main project
File projectBuildFile = file('../build.gradle')
//Use this parse command because Groovy wants to use the file name as the classname
//which fails if your Gradle build file has been renamed to contain an invalid character (i.e. '-')
DelegatingScript script = (DelegatingScript)sh.parse(projectBuildFile.text, 'GradlePlugins')
script.setDelegate(holder)
//Resolve the project main Gradle file against our ScriptHolder
script.run()
//Class for holding the evaluation of a Gradle script
//You may need to add some extra methods here depending on what you have all placed in build.gradle
class ScriptHolder {
Closure dependencies
void dependencies(Closure c) {
this.dependencies = c
}
void apply(Map map) {
}
}
//Grab the dependencies closure and resolve it against
//the buildSrc project dependencies
//This effectively applies the same dependenices from build.gradle into buildSrc/build.gradle
//This is required so that when buildSrc is compiled it has the dependencies to compile the source code
def closure = holder.dependencies.clone()
closure.delegate = project.dependencies
closure()
@wheelerlaw
Copy link

wheelerlaw commented Jun 5, 2018

@CliveEvans I also couldn't get @johnrengelman script to work for me, although its likely because of the version of Gradle I am running. This was my error:

No signature of method: GradlePlugins.buildscript() is applicable for argument types: (GradlePlugins$_run_closure1) values: [GradlePlugins$_run_closure1@2e7cad0f]

@hakanai
Copy link

hakanai commented Feb 26, 2019

@wheelerlaw hard to know without the stack trace, but did you have buildscript defined in ScriptHolder?

@ncimino
Copy link

ncimino commented Oct 26, 2021

I'm seeing this error while trying to upgrade Gradle 6.8 to 7.2 (and JUnit 4 to 5, etc.):

No signature of method: GradlePlugins.test() is applicable for argument types: (GradlePlugins$_run_closure5) values: [GradlePlugins$_run_closure5@4a6f4fd5]
  Possible solutions: wait(), getAt(java.lang.String), use([Ljava.lang.Object;), wait(long), tap(groovy.lang.Closure), is(java.lang.Object)

This error is related to adding this code:

test {
    useJUnitPlatform()
}

Any ideas on how to fix this?

@ncimino
Copy link

ncimino commented Oct 26, 2021

I found it - I had to add:

class ScriptHolder {
    ...see gist...

    Closure test
    void test(Closure c) {
        this.test = c
    }
}

def test = holder.test.clone()
test.delegate = project.test
test()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment