-
-
Save johnrengelman/9a20697b2246a9bfaca2 to your computer and use it in GitHub Desktop.
//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() |
Worked like a charm for me, thank you!
@ysb33r, your approach has two drawbacks:
- It doesn't apply plugin dependencies to your build script. You need to combine both approaches to get it done, or provide dependencies to build script separately. @johnrengelman's approach doesn't apply plugin, it only copies dependencies, so both are required.
- Recent versions of Gradle say that script passed to
loadScriptByName
shouldn't contain apackage
statement.
I looked for a solution and found out that much nicer and cleaner way is to compile plugin in buildSrc
and then apply its class to the main project. It is in the Gradle documentation.
@grv87 unless I'm missing something, you can't use buildSrc if you're also publishing your plugin. The method used by @ysb33r works, you just need to remember to add any dependencies to your buildscript dependencies (as classpath dependencies).
The script from @johnrengelman, OTOH, just didn't work for me. And it was far from clear why ...
@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]
@wheelerlaw hard to know without the stack trace, but did you have buildscript
defined in ScriptHolder
?
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?
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()
This is a pretty fancy example.
Have you considered a simpler approach such as below
or is that not sufficient for your needs?