I've written a Gradle Plugin in Groovy under buildSrc as:
package test
import org.gradle.api.Plugin
import org.gradle.api.Project
class SamplePlugin implements Plugin<Project> {
#Override
void apply(Project project) {
println "This line prints" //Just for Configuration. This prints
def sample = project.tasks.create("sample") {
doLast {
println "This line does not print"
}
}
project.configure(project) {
sample.mustRunAfter('check')
}
}
}
Here, I'm trying to run the sample task at the end of my build, so I have it run after check
I now try to call it in my projects build.gradle file that looks like:
buildscript {
repositories {
mavenLocal()
mavenCentral()
}
}
apply plugin: 'java'
apply plugin:'application'
apply plugin: test.SamplePlugin
repositories {
mavenLocal()
mavenCentral()
}
mainClassName = "test.Widget"
Unfortunately, I don't see that it runs i.e. the code in the doLast does not appear in the output, but the configuration code does:
:buildSrc:compileJava NO-SOURCE
:buildSrc:compileGroovy
:buildSrc:processResources UP-TO-DATE
:buildSrc:classes
:buildSrc:jar
:buildSrc:assemble
:buildSrc:compileTestJava NO-SOURCE
:buildSrc:compileTestGroovy NO-SOURCE
:buildSrc:processTestResources NO-SOURCE
:buildSrc:testClasses UP-TO-DATE
:buildSrc:test NO-SOURCE
:buildSrc:check UP-TO-DATE
:buildSrc:build
This line prints
:compileJava UP-TO-DATE
:processResources NO-SOURCE
:classes UP-TO-DATE
:jar UP-TO-DATE
:startScripts UP-TO-DATE
:distTar UP-TO-DATE
:distZip 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
BUILD SUCCESSFUL in 1s
5 actionable tasks: 5 up-to-date
I'd be grateful for any help or pointers
Edit: As M.Ricciuti commented below order matters, so I have moved the test.SamplePlugin after the plugin java. Otherwise, please follow lu.koerfers solution of using the pluginManager.
In your plugin you are creating a new task 'sample' and set a constraint "sample must run after check": but this does not include the sample task in the task graph . It just says: "if sample and check tasks are both executed , then check task must be executed first". So if you just execute 'gradle build', this will not trigger execution of task "sample".
Try to execute directly "gradle sample" : you will see it will trigger its execution, and make the execution of "check" task first in respect of the contraint you have defined in plugin.
If you want to make "sample" task execute each time you execute "build" task, then just set a "dependsOn" constraint between "build" and "sample" tasks, in your plugin:
class SamplePlugin implements Plugin<Project> {
#Override
void apply(Project project) {
println "This line prints" //Just for Configuration. This prints
def sample = project.tasks.create("sample") {
doLast {
println "This line does not print"
}
}
project.configure(project) {
sample.mustRunAfter('check')
project.getTasks().findByName('build').dependsOn(sample) // <== set this contraint
}
}
}
EDIT : to avoid having to rely on plugin apply order, the task dependency declaration could be wrapped in a "afterEvaluate" block:
void apply(Project project) {
// task 'sample' def ...
// ...
project.configure(project) {
project.afterEvaluate {
sample.mustRunAfter('check')
project.getTasks().findByName('build').dependsOn(sample)
}
}
The methods mustRunAfter and shouldRunAfter only define execution order, not causality. That means that they won't cause a task to be executed. But if both tasks are executed, the specified order will be taken into account.
To specify a task dependency, use dependsOn or finalizedBy:
project.pluginManager.withPlugin('java') {
project.tasks.getByName('check').finalizedBy('sample');
}
This would cause sample to run everytime check runs and it ensures that it runs after check.
Related
I am a bit puzzle about how gradle in IntelliJ resolve the task name
For example, build.gradle has following content:
plugins {
id 'java'
id 'org.gauge' version '1.8.1'
}
group 'com.example'
version '0.0.1-SNAPSHOT'
sourceCompatibility = 1.11
targetCompatibility = 1.11
repositories {...}
dependencies {...}
task gaugeTestLocal(type: GaugeTask) {
doFirst {
gauge {
specsDir = 'specs'
inParallel = false
nodes = 3
env = 'stg'
additionalFlags = '--verbose'
}
}
}
task downloadDependencies {...}
Using IntelliJ Gradle with command gradle gaugeTe, it somehow knows to run gaugeTestLocal instead.
How is this made possible behind the scene?
Run output
> Task :compileJava NO-SOURCE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :compileTestJava UP-TO-DATE
> Task :processTestResources UP-TO-DATE
> Task :testClasses UP-TO-DATE
> Task :gaugeTestLocal
I'd like to pass a closure as configuration for a plugin. Here is a minimal version of it:
package org.samuel.gradle.plugins
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
class TestPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create("testConfig", TestConfig)
Task test = project.task("testTask") {
doFirst {
println "The message is already " + project.extensions.testConfig.message
println "Trying to run closure " + project.extensions.testConfig.closure
project.extensions.testConfig.closure()
println "did it run?"
}
}
}
}
class TestConfig {
String message = "Testing ..."
Closure closure = {
println("running closure")
}
}
This doesn't work, the closure is never evaluated (nor at configuration nor when I intend it to:
$ ./gradlew test
:buildSrc:compileJava UP-TO-DATE
:buildSrc:compileGroovy
:buildSrc:processResources UP-TO-DATE
:buildSrc:classes
:buildSrc:jar
:buildSrc:assemble
:buildSrc:compileTestJava UP-TO-DATE
:buildSrc:compileTestGroovy UP-TO-DATE
:buildSrc:processTestResources UP-TO-DATE
:buildSrc:testClasses UP-TO-DATE
:buildSrc:test UP-TO-DATE
:buildSrc:check UP-TO-DATE
:buildSrc:build
:testTask
The message is already Testing ...
Trying to run closure org.samuel.gradle.plugins.TestConfig$_closure1#5600ea3b
did it run?
BUILD SUCCESSFUL
Total time: 1.569 secs
I think I am missing something about how gradle evaluates the contents of the extensions. Is it possible to somehow pass something via an extension and evaluate it in a task in the plugin?
The solution is surprisingly unimpressive. Change the line for calling the closure to:
project.extensions.testConfig.closure.call()
Notice the use of .call() vs just calling ()
Also noticed that this calls the closure:
println "Trying to run closure ${project.extensions.testConfig.closure}"
Why?
My WAR file should contain Java source files from components.
In my root project build.gradle I am executing tasks in subprojects programmatically:
apply plugin: 'war'
jar.enabled = false
war {
// - Copy Java source files to the folder corresponding to the component;
into("/") { from { collectFilesFromCopyTask('copySourceFiles') } }
}
// Collects files from destinationDirs of copy tasks with matching taskName
def collectFilesFromCopyTask(taskName) {
FileCollection collectedFiles = files{}
// for each task in subprojects
subprojects.each {project ->
project.tasks.withType(Copy).matching { task -> task.name.equals( taskName ) }.each { copyFilesTask ->
println 'copyFilesTask.destinationDir=' + copyFilesTask.destinationDir
// execute task
copyFilesTask.execute()
// add destinationDir of the task to the collected files
collectedFiles += files(copyFilesTask.destinationDir)
}
}
return collectedFiles
}
In subproject I have task:
task copySourceFiles(type: Copy) {
destinationDir = file(project.buildDir.name + '/sourceFiles')
into('componentName') {
from(project.projectDir)
exclude('build')
exclude('bin')
exclude('src/main/webapp')
exclude('.gradle')
}
}
Console output:
[sts] -----------------------------------------------------
[sts] Starting Gradle build for the following tasks:
[sts] clean
[sts] build
[sts] -----------------------------------------------------
copyFilesTask.destinationDir=<...>application1\build\sourceFiles
:clean
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:war
copyFilesTask.destinationDir=<...>application1\build\sourceFiles
copyFilesTask.destinationDir=<...>application1\build\sourceFiles
copyFilesTask.destinationDir=<...>application1\build\sourceFiles
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
, which means that collectFilesFromCopyTask() is executed 4 times.
It should be executed only once, from WAR task.
Never ever use the .execute() method of a task in Gradle.
Except of when ...... no, never ever do that.
It is not a supported thing to do and does probably not work as expected.
Always use task dependencies or task ordering dependencies to make sure dependent tasks are run or tasks are run in a specific order if they both run but otherwise do not depend on each other directly.
Make your war task depend on your copy tasks and make your war task use the outputs of those tasks (not a manual files(...) call).
EDIT:
war {
into("/") { from { subprojects.tasks*.findByName('copySourceFiles').findAll { it instanceof Copy } } }
}
I have a task of Type: Test. When I run the task, it just says UP-TO-DATE and does not run the test that is, it does not execute the action in the doLast part of the task. Can you please help?
Thanks!
task runIntegrationTests(type: Test) {
dependsOn compileIntegrationTestJava, processIntegrationTestResources, processTestResources
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
doLast {
logger.info("running Cuke tests")
(new File('build/test-results')).mkdirs()
javaexec {
main = "cucumber.api.cli.Main"
classpath = sourceSets.integrationTest.runtimeClasspath
args = ['--format', 'pretty',
'--format', 'html:build/test-results/cucumber-html',
'--format', 'json:build/test-results/cucumber.json',
'--tags', '~#wip',
'--format', 'junit:build/test-results/cuke-junit-results.xml',
'--glue', 'src/integration/groovy', 'src/integration/resources']
}
}
}
:cleanTest UP-TO-DATE
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE
:compileTestJava UP-TO-DATE
:compileTestGroovy UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build UP-TO-DATE
:compileIntegrationTestJava UP-TO-DATE
:compileIntegrationTestGroovy UP-TO-DATE
:processIntegrationTestResources UP-TO-DATE
:integrationTestClasses UP-TO-DATE
:runIntegrationTests UP-TO-DATE
BUILD SUCCESSFUL
You must declare inputs and outputs for your task in order to make it run. If no inputs to the task has changed it does not run. Add e.g. sourceset to your inputs. Take a look at the gradle docs, https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:up_to_date_checks
E.g:
task transform {
inputs.file srcFile
outputs.dir destDir
...
}
I want to setup simple dependency between tasks.
My build.gradle
apply plugin: 'java'
sourceCompatibility = 1.8
version = '1.0'
repositories {
mavenCentral()
}
task('Second', dependsOn: 'First') {
println "Second"
}
task('First') {
println "First"
}
As a result I expect First and than Second.
But I've got:
$ gradle build
Second
First
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build UP-TO-DATE
What am I doing wrong?
Thanks for help.
Still the same error.. You're at configuration phase. Add actions to task and everything will be fine. This will work:
apply plugin: 'java'
sourceCompatibility = 1.8
version = '1.0'
repositories {
mavenCentral()
}
task('Second', dependsOn: 'First') << {
println "Second"
}
task('First') << {
println "First"
}
This is a configuration phase:
task t1 {
println "t1"
}
Code in configuration phase is executed before action. Adding action is done with << (leftShift) operator.
task t1 << {
println "t1"
}
Here are the docs.
<< is just overridden operator do doLast method. Without it it will be:
apply plugin: 'java'
sourceCompatibility = 1.8
version = '1.0'
repositories {
mavenCentral()
}
task('Second', dependsOn: 'First') {
doLast {
println "Second"
}
}
task('First') {
doLast {
println "First"
}
}
I also encourage you to read this blog post.