Configure Zip/Copy Task in a Plugin with Gradle - gradle

I am trying to create an Zip task in a plugin:
class MyPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
Zip buildFunctionArchive = project.tasks.create("buildFunctionArchive", Zip.class) {
archiveClassifier = "yolo"
from(project.getTasksByName("compileJava", true))
}
}
}
But for some reason even though the compileJava task exists in the project form which I use my plugin. When I print debug output I get: NO-SOURCE
2020-10-05T02:16:03.565+1100 [LIFECYCLE] [class org.gradle.internal.buildevents.TaskExecutionLogger] > Task :buildFunctionArchive NO-SOURCE
If I configure the from in my client project:
buildFunctionArchive{
from compileJava
}
This works, and I even see the yolo in the archive name. But if I remove the from compileJava
buildFunctionArchive{
}
As well as removing the configuration all together and running gradle buildFunctionArchive
The task will not create the archive, even though I have configured this in the MyPlugin class, I will get the NO-SOURCE error. What am I missing? I am wanting to define a Zip task in my plugin but am having no luck.

Related

In a custom gradle plugin, how to add task depends on task which is defined in other plugin?

for example, I have a plugin:
public class PluginA implements Plugin.
and I will create a task taskA. Now I want to set: taskA.dependsOn taskB, but taskB is defined in PluginB.
Does it possible to do this, if can, how to do it?
You don't need to know that taskB comes from PluginB to create the dependency on taskA: you can simply reference taskB by its name, as follows:
class PluginA implements Plugin<Project> {
void apply(Project project) {
Task taskA = project.task('taskA') {
doLast {
println 'Executing task A from plugin A'
}
}
// create dependency from taskA to taskB
project.tasks.matching { it.name == 'taskB'}.each {
taskA.dependsOn it
}
}
}
Please note that if your consuming project which applies PluginA does not apply PluginB, the dependency will not be created. Maybe you want/need to automatically apply PluginB when applying PluginA.
Another way would be to create this dependency only when pluginB is applied, using pluginManager.withPlugin method:
class PluginA implements Plugin<Project> {
void apply(Project project) {
Task taskA = project.task('taskA') {
doLast {
println 'Executing task A from plugin A'
}
}
project.pluginManager.withPlugin('pluginB'){
println "pluginB applied => adding dependency from taskA to taskB"
project.afterEvaluate{
taskA.dependsOn project.tasks.getByName('taskB')
}
}
}
}

why "jar.enabled = false" affects dependencies in Gradle?

The story:
I have recently discovered that setting jar.enabled = false in project b-features of a multi-projects Gradle project will stop project a-features of the same project from being able to refer to B via
dependencies {
compile project(':b-features')
}
The question:
Why is jar.enabled = false stopping project A from successfully referring to project B?
Additional info:
build.gradle of the root project:
group 'gradle.studies'
apply plugin: 'java'
...
settings.gradle of the root project:
rootProject.name = 'multi-project-reference'
include 'a-features'
include 'b-features'
build.gradle of the project a-features:
group 'gradle.studies'
apply plugin: 'java'
...
dependencies {
compile project(':b-features')
}
...
build.gradle of the project b-features
group 'gradle.studies'
apply plugin: 'java'
jar.enabled = false
...
Class A in a-features project:
package outerproject;
import innerproject.B;
public class A {
public static void main(String[] args) {
B b = new B();
System.out.println(b.getMsg());
}
}
Class B in b-features project:
package innerproject;
public class B {
public B() {
this.msg = "Hello World";
}
private String msg;
public String getMsg() {
return msg;
}
//...
}
The error:
14:27:50: Executing external task 'build'...
:compileJava NO-SOURCE :processResources NO-SOURCE :classes UP-TO-DATE
:jar UP-TO-DATE :assemble UP-TO-DATE :compileTestJava NO-SOURCE
:processTestResources NO-SOURCE :testClasses UP-TO-DATE :test
NO-SOURCE :check UP-TO-DATE :build UP-TO-DATE :b-features:compileJava
UP-TO-DATE :b-features:processResources NO-SOURCE :b-features:classes
UP-TO-DATE :b-features:jar SKIPPED
/home/nikita/IdeaProjects/multi-project-reference/a-features/src/main/java/outerproject/A.java:3:
error: package innerproject does not exist import innerproject.B;
^ /home/nikita/IdeaProjects/multi-project-reference/a-features/src/main/java/outerproject/A.java:7:
error: cannot find symbol
B b = new B();
^ symbol: class B location: class A /home/nikita/IdeaProjects/multi-project-reference/a-features/src/main/java/outerproject/A.java:7:
error: cannot find symbol
B b = new B();
^ symbol: class B location: class A 3 errors :a-features:compileJava FAILED
FAILURE: Build failed with an exception.
What you actually depend on, is the artifact (JAR file) that is produced by the project. As you disabled the generation of the artifact (jar task), the needed classes of course are not found any longer.

Is there a Gradle task to download testRuntime dependencies?

Is there a command that will instruct Gradle to resolve and download all testRuntime dependencies, but not run the tests?
Preferably, I want to do this without writing a custom task (such that the command can be run against any Gradle project).
For example, if my build.gradle has this dependency:
dependencies {
// ...
testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
}
The JAR files associated with selenium-htmlunit-driver are not downloaded until I run gradle test, which also runs the tests. I can download all other dependencies by running gradle testClasses, but not the testRuntime deps.
Put the following in a file called resolve.gradle
gradle.allprojects { project ->
project.task('resolveTestRuntime') {
doLast {
project.configurations.testRuntime.resolve()
}
}
}
Then run resolve.gradle as an init script
gradlew --init-script resolve.gradle resolveTestRuntime
Modifying the answer from Lance Java into a valid Init script, I was able to accomplish this with the following resolve.gradle:
apply plugin:MyInitPlugin
class MyInitPlugin implements Plugin<Gradle> {
#Override
void apply(Gradle gradle) {
gradle.allprojects{ project ->
project.task('resolveTestRuntime') {
doLast {
project.configurations.testRuntime.resolve()
}
}
}
}
}
Then running:
gradlew --init-script resolve.gradle resolveTestRuntime

Can't run a jar-file, built from groovy-code compiled with gradle

I'm trying to compile (with gradle) and execute (with the java 1.8 runtime) a small groovy program (see helloWorld.groovy, below).
But when I try to invoke it, I get Error: Could not find or load main class helloWorld
What am I missing?
compile:
lexu> gradle clean jar
:clean
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
BUILD SUCCESSFUL
Total time: 0.555 secs
execute:
lexu> java -jar ./build/libs/helloWorld.jar
Error: Could not find or load main class helloWorld
helloWorld.groovy:
class helloWorld {
static void main(String[] args) {
println('Hello World');
}
}
build.gradle:
apply plugin: 'groovy'
apply plugin: 'application'
mainClassName = "helloWorld"
archivesBaseName = 'helloWorld';
configurations {provided; inlib;}
repositories {mavenCentral()}
dependencies {compile 'org.codehaus.groovy:groovy-all:2.4.7'}
jar {
manifest {
attributes(
'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
'Main-Class': 'helloWorld'
)
}
}
There are a couple of issues with your setup.
Not breaking, but worth mentioning here: Convention states your filenames and classes should be uppercase: HelloWorld.groovy
gradle assumes your source files to be under src/main/java or in this case, src/main/groovy. You can configure it according to your preferences with gradle groovy plugin - project layout:
sourceSets {
main {
groovy {
srcDirs = ['src/groovy']
}
}
}
You need to include all runtime dependencies for groovy in your jar-archive. For this, let's use use an extended task called uberjar.
build.gradle:
apply plugin: 'groovy'
apply plugin: 'application'
mainClassName = "HelloWorld"
archivesBaseName = 'HelloWorld';
configurations {provided; inlib;}
repositories {mavenCentral()}
dependencies {compile 'org.codehaus.groovy:groovy-all:2.4.7'}
task uberjar(type: Jar,dependsOn:[':compileJava',':compileGroovy']) {
from files(sourceSets.main.output.classesDir)
from configurations.runtime.asFileTree.files.collect { zipTree(it) }
manifest {
attributes 'Main-Class': mainClassName
}
}
HelloWorld.groovy:
class HelloWorld {
static void main(String[] args) {
println('Hello World');
}
}

gradle custom task execution phase

This question is for gradle (>= 2.4). I would like to write a custom task like the following:
https://docs.gradle.org/current/userguide/custom_tasks.html
class GreetingTask extends DefaultTask {
#TaskAction
def greet() {
println 'hello from GreetingTask'
}
}
task hello(type: GreetingTask)
how can I make this task run during execution phase? Is passing an empty closure with
<< {
}
the only solution?
Edit
the task is supposed to be used in a multiproject build with several tasks as dependencies.
I'd like that the command gradle build would build all the projects by saying something like
`build.dependsOn(hello)`
but seems that the task hello is called during configuration phase of the build.
Add the following to a build.gradle file:
class GreetingTask extends DefaultTask {
#TaskAction
def greet() {
println 'hello from GreetingTask'
}
}
task hello(type: GreetingTask) {
println "This is the configuration phase"
doFirst {
println "This is the execution phase"
}
}
Now execute gradle hello. The output you will see is
This is the configuration phase
:hello
This is the execution phase
hello from GreetingTask
BUILD SUCCESSFUL
As you can see, the output from the task occurs after the doFirst(), which definitely happens during the execution phase.

Resources