If a condition is not met, I am trying to stop execution of a task using onlyIf(). Is there a way I can stop the task dependencies too from executing? Seems onlyIf does not stop dependencies from execution.
In the example below, I desire taskA not executed when I pass executeMe parameter as false.
build.gradle
task taskA() {
doFirst {
println 'executing taskA'
}
}
task taskB(dependsOn: 'taskA') {
onlyIf {
executeMe.toBoolean()
}
doFirst {
println 'executing taskB'
}
}
Run output:
>gradle taskB -PexecuteMe=false
10:39:36 AM: Executing external task 'taskB -PexecuteMe=false'...
:taskA
executing taskA
:taskB SKIPPED
One way you can achieve this is by adding "onlyIf" to both tasks at the same time using the following:
task taskA() {
doFirst {
println 'executing taskA'
}
}
task taskB(dependsOn: 'taskA') {
doFirst {
println 'executing taskB'
}
}
[taskA, taskB].each { task ->
task.onlyIf {
executeMe.toBoolean()
}
}
Output:
$ gradle taskB -PexecuteMe=false
:taskA SKIPPED
:taskB SKIPPED
BUILD SUCCESSFUL
Total time: 2.122 secs
Related
I try to investigate a Gradle and follows some tutorials, but I have confused with the following:
I created are a couple of simple tasks:
task startProcess{
println 'startProcess'
}
task doStep2{
println 'Step2'
}
task doStep3{
println 'Step3'
}
task finishProcess{
println 'finishProcesss'
}
And try to execute one of them:
gradle finishProcess
Or with defaultTasks with command gradle build:
defaultTasks `finishProcess`
task startProcess{
println 'startProcess'
}
task doStep2{
println 'Step2'
}
task doStep3{
println 'Step3'
}
task finishProcess{
println 'finishProcesss'
}
In both options, I got the same result:
> Configure project :
startProcess
Step2
Step3
finishProcesss
BUILD SUCCESSFUL in 1s
How to execute exactly one of them?
You have to use register, I think if you did not use it, You're only asking Gradle to execute these tasks.
for example
tasks.register('startProcess') {
doLast {
println 'startProcess'
}
}
tasks.register('doStep2') {
doLast {
println 'Step2'
}
}
tasks.register('doStep3') {
doLast {
println 'Step3'
}
}
tasks.register('finishProcess') {
doLast {
println 'finishProcesss'
}
}
tasks.named("build") { finalizedBy("finishProcess") }
Registering these tasks, you will be able to call each one indivadually.
If you want to link a specific task, with a build task for example.
Then you can use finalizedBy like the following.
tasks.named("build") { finalizedBy("finishProcess") }
This will call the finishProcess task, whenever build is triggered.
I strongly recommend the official gradle documintation for more information about tasks.
I'm trying to get Gradle's mustRunAfter and finalizedBy to work only for a specific task. Take this example build.gradle:
task removeTestDatabaseContainer {
doLast {
println '\ninside removeTestDatabaseContainer\n'
}
}
task startTestDatabaseContainer {
doLast {
println '\ninside startTestDatabaseContainer\n'
}
finalizedBy removeTestDatabaseContainer
}
task flywayMigrate { t->
doLast {
println '\n inside flywayMigrate\n'
}
}
task flywayClean { t->
doLast {
println '\n inside flywayClean\n'
}
}
task testEverything {
dependsOn startTestDatabaseContainer
dependsOn flywayMigrate
dependsOn flywayClean
flywayMigrate.mustRunAfter startTestDatabaseContainer
flywayMigrate.finalizedBy flywayClean
flywayClean.mustRunAfter flywayMigrate
flywayClean.finalizedBy removeTestDatabaseContainer
}
I'm happy with how testEverything works. I want the output I'm getting from that task:
➜ gradle testEverything
Parallel execution is an incubating feature.
:startTestDatabaseContainer
inside startTestDatabaseContainer
:flywayMigrate
inside flywayMigrate
:flywayClean
inside flywayClean
:removeTestDatabaseContainer
inside removeTestDatabaseContainer
:testEverything
BUILD SUCCESSFUL
Total time: 0.597 secs
However, when I run only flywayMigrate I get unexpected problems. This is the output:
➜ gradle flywayMigrate
Parallel execution is an incubating feature.
:flywayMigrate
inside flywayMigrate
:flywayClean
inside flywayClean
:removeTestDatabaseContainer
inside removeTestDatabaseContainer
BUILD SUCCESSFUL
Total time: 0.605 secs
This is not the output I want. I would like only flywayMigrate to run. Question 1) How can I make testEverything work as it does and at the same time have gradle flywayMigrate invoke only the flywayMigrate-task?
Question 2)
I'm told this has something to do with the fact that everything inside the brackets of task testEverything {} is configuration, which is always processed by Gradle. So any mustRunAfter/finalizedBy I set within a task will have "global effect". But in that case, why doesn't gradle flywayMigrate invoke startTestDatabaseContainer? (Because of the line flywayMigrate.mustRunAfter startTestDatabaseContainer inside the testEverything task.)
Edit: I was directed to Ordering tasks and Finalizer tasks in the Gradle documentation and they answer question 2: mustRunAfter only takes effect when both tasks are ran. finalizedBy on the other hand takes effect when only the task it is set on is ran. That answers why flywayClean and removeTestDatabasContainer are ran when I execute gradle flywayMigrate.
I'm still struggling to make gradle testEverything work as it does above and at the same time get gradle flywayMigrate to just execute flywayMigrate.
Thanks to the help of eskatos on #gradle on Freenode I found a solution. It was simply to remove the finalizedBy-lines i had. Updated build.gradle that works:
task removeTestDatabaseContainer {
doLast {
println '\ninside removeTestDatabaseContainer\n'
}
}
task startTestDatabaseContainer {
doLast {
println '\ninside startTestDatabaseContainer\n'
}
finalizedBy removeTestDatabaseContainer
}
task flywayMigrate { t->
doLast {
println '\n inside flywayMigrate\n'
}
}
task flywayClean { t->
doLast {
println '\n inside flywayClean\n'
}
}
task testEverything {
dependsOn startTestDatabaseContainer
dependsOn flywayMigrate
dependsOn flywayClean
flywayMigrate.mustRunAfter startTestDatabaseContainer
//flywayMigrate.finalizedBy flywayClean
flywayClean.mustRunAfter flywayMigrate
//flywayClean.finalizedBy removeTestDatabaseContainer
}
I have these gradle tasks:
- startTestDatabaseContainer: builds and starts a docker container with a database
- removeTestDatabaseContainer: stops and removes the docker container
- flywayValidate: a task from org.flywaydb.flyway that validates my migration files
I wish to run these three tasks in order. Reading this leads me to this solution:
flywayValidate.dependsOn startTestDatabaseContainer
flywayValidate.finalizedBy removeTestDatabaseContainer
This works ok, but then I can't run gradle flywayValidate from the commandline without startTestDatabaseContainer and removeTestDatabaseContainer also being invoked. I want to be able to run flywayValidate without that happening.
What can I do to accomplish this when I cannot have ordered dependencies in gradle?
My first attempt was simply:
task validateMigration {
dependsOn startTestDatabaseContainer
dependsOn flywayValidate
finalizedBy removeTestDatabaseContainer
}
But that fails because flywayValidate can run before startTestDatabaseContainer.
Edit: I've setup a demonstration base on Opal's solution here: github.com/stianlagstad/flyway-migration-error-causes-final-gradle-task-to-not-execute. Clone it and run gradle validateMigration. The migration will fail and the final gradle task won't run (and docker ps will show the container still running). If you fix the migration file then everything works as expected. I'm sure I'm misunderstanding something. Any pointers would be helpful!
The following setup should meet all your requirements:
task startTestDatabaseContainer {
doLast {
println 'startTestDatabaseContainer'
}
}
task flywayValidate {
doLast {
println 'flywayValidate'
}
}
task removeTestDatabaseContainer {
doLast {
println 'removeTestDatabaseContainer'
}
}
task validateMigration {
dependsOn startTestDatabaseContainer
dependsOn flywayValidate
flywayValidate.mustRunAfter startTestDatabaseContainer
finalizedBy removeTestDatabaseContainer
}
EDIT
task removeTestDatabaseContainer {
doLast {
println 'removeTestDatabaseContainer'
}
}
task startTestDatabaseContainer {
doLast {
println 'startTestDatabaseContainer'
}
finalizedBy removeTestDatabaseContainer
}
task flywayValidate { t->
doLast {
println 'flywayValidate'
throw new TaskExecutionException(t, new RuntimeException('whatever'))
}
}
task validateMigration {
dependsOn startTestDatabaseContainer
dependsOn flywayValidate
flywayValidate.mustRunAfter startTestDatabaseContainer
}
Here's a demo.
task validateMigration {
dependsOn startTestDatabaseContainer
dependsOn flywayMigrate
flywayMigrate.finalizedBy removeTestDatabaseContainer
flywayMigrate.mustRunAfter startTestDatabaseContainer
}
This did the trick! Thank you orzeh for the PR on Github, and thank you Opal for the help!
I am facing an issue related to gradle task dependencies. One of my gradle task is calling another task successfully but it is not executing dependencies on which my second task depends. Please go through the following code to understand the problem statement:
My code is:
task callGradleDeploy <<{
tasks.deployComp.execute()
}
task deployComp (dependsOn: ['setEnvParameter', 'installWeb', 'installService']) <<{
println "Deployment Done"
}
task setEnvParameter {
//parameter Setting for deployement
}
task installWeb {
//install Web Code
}
task installService {
//install Services Code
}
Now when I run task callGradleDeploy, it is calling deployComp task but it is not installing Web or Service content (Not doing anything with setEnvParameter, installWeb, installService ). and Just printing Deployment Done
Just to notify, when I am individually calling(running) deployComp task, it is installing Web and Service part without any issue.
Please help me to understand how to manage this dependsOn thing while calling a gradle task into another.
Second part:
*//******************* Edited part below, For clear understanding *****************//*
#Opal I have done configuration like below after your suggestion.
For the cases, where only deployService should work. It is still calling deployWeb and deployWebAndService both.
Code is here:
task deploy (dependsOn : ['deployWeb', 'deployService', 'deployWebAndService']) <<{
println "\n\tExecuting respective task"
}
task deployWeb (dependsOn : ['configureWebApp','stopWebApp','uninstallWebApp','installWebApp','startWebApp']) <<{
println "\n\tExecuting deploy for Web Content"
}
task deployService (dependsOn : ['configureService','stopService','uninstallService','installService','startService']) <<{
println "\n\tExecuting deploy for Service Content"
}
task deployWebAndService (dependsOn : ['configureWebApp','configureService','stopWebApp','uninstallWebApp','installWebApp','startWebApp','stopService','uninstallService','installService'/*,'startService'*/]) <<{
println "\n\tExecuting deploy for Web and Service Content"
}
deployWeb.onlyIf{
(WebContent.equals("Yes") && ServiceContent.equals("No")) //fetching "Yes"/"No" values from a separate function
}
deployService.onlyIf{
(WebContent.equals("No") && ServiceContent.equals("Yes"))
}
deployWebAndService.onlyIf{
(WebContent.equals("Yes") && ServiceContent.equals("Yes"))
}
TL;DR Your build.gradle should look as follows:
task callGradleDeploy(dependsOn: ['deployComp']) {
}
task deployComp (dependsOn: ['setEnvParameter', 'installWeb', 'installService']) <<{
println "Deployment Done"
}
task setEnvParameter{
//parameter Setting for deployement
}
task installWeb{
//install Web Code
}
task installService{
//install Services Code
}
First of all you should never call task's execute() method manually, since this highly discouraged and interferes gradle's internal logic (directed acyclic graph). To define dependencies between tasks the following methods should be used:
mustRunAfter
shouldRunAfter
dependsOn
In your particular case it's enough to substitute execute invocation with dependsOn and it works perfectly. Also please note the << to indicate action is deprecated and scheduled to be removed in version 5.0. Instead use doLast:
task callGradleDeploy {
doLast { println 'action' }
}
EDIT
See the solution below. The advantage is that you configure dependencies between tasks once. To check if it works correctly run gradle deploy -Pwc or gradle deploy -Psc
task explodeWarContent {
doLast {
println 'Code to explode war'
}
}
task configureWebApp(dependsOn: explodeWarContent) {
doLast {
println 'Code to configure web app'
}
}
task stopWebApp {
doLast {
println 'Code to stop web app'
}
}
task uninstallWebApp(dependsOn: stopWebApp) {
doLast {
println 'Code to uninstall web app'
}
}
task installWebApp(dependsOn: configureWebApp) {
mustRunAfter uninstallWebApp
doLast {
println 'Code to install web app'
}
}
task startWebApp(dependsOn: installWebApp) {
mustRunAfter stopWebApp
doLast {
println 'Code to start web app'
}
}
task deployWebApp(dependsOn: [uninstallWebApp, startWebApp]) {
onlyIf { project.hasProperty('wc')}
}
task configureService {
doLast {
println 'Code to configure service'
}
}
task stopService {
doLast {
println 'Code to stop service'
}
}
task uninstallService(dependsOn: stopService) {
doLast {
println 'Code to uninstall service'
}
}
task installService(dependsOn: configureService) {
mustRunAfter uninstallService
doLast {
println 'Code to install service'
}
}
task startService(dependsOn: installService) {
mustRunAfter stopService
doLast {
println 'Code to start service'
}
}
task deployService(dependsOn: [uninstallService, startService]) {
onlyIf { project.hasProperty('sc')}
}
task deploy {
dependsOn deployWebApp, deployService
}
I have the following in build.gradle:
task aoeu << {
println "**************************** during"
}
tasks.publish.dependsOn(aoeu)
tasks.publish.doFirst {
println "************************* before"
}
tasks.publish.doLast {
println "************************* after"
}
Its output is:
:aoeu
**************************** during
:publish
************************* before
************************* after
But what I really need is for the 'during' to happen between 'before' and 'after'. How can this be done? Should 'publish' simply depend on 'before'? If so, how can I guarantee that it happen before other dependencies?
As far as I know your code should work propertly but it doesn't. doFirst should be executed in configuration phase which is run before doLast (execution phase). BTW this code works fine:
As Peter Niederwiser wrote here https://stackoverflow.com/a/9204159/2069368 doFirst run in execution phase as first statement (before doLast) so your code works fine. This example will show you execution order in gradle build:
task publish {
println "(1) before (run in configuration phase)" // this will run before gradle dependencies
}
task aoeu << {
println "(2) during (run in execution phase as last statement)"
}
tasks.publish.dependsOn(aoeu)
tasks.publish.doLast {
println "(4) after (run in execution phase as last statement)"
}
tasks.publish.doFirst {
println "(3) after (run in execution phase as FORST statement - before doLast/<<)"
}
It will return
C:\>gradle publish
(1) before (run in configuration phase)
:aoeu
(2) during (run in execution phase as last statement)
:publish
(3) after (run in execution phase as FORST statement - before doLast/<<)
(4) after (run in execution phase as last statement)
[UPDATE]
Here http://gradle.1045684.n5.nabble.com/task-run-order-lt-lt-syntax-doLast-doFirst-etc-td3337481.html is great question with great example which shows execution order.
Read this article about gradle lifecycle, it will help you understand it.
[UPDATE]
If you want to run task aoeu in publish execution phase you can call aoeu.execute in publish.doFirst. But as far as I know it shouldn't be done in that way.
task publish {
}
task aoeu << {
println "(2) during (run in execution phase as last statement)"
}
tasks.publish.doLast {
println "(3) after (run in execution phase as last statement)"
}
tasks.publish.doFirst {
println "(1) after (run in execution phase as FORST statement - before doLast/<<)"
aoeu.execute()
}
will return
C:\>gradle publish
:publish
(1) after (run in execution phase as FORST statement - before doLast/<<)
(2) during (run in execution phase as last statement)
(3) after (run in execution phase as last statement)
As I see you want to run aoeu in the middle of publish task. I think that the best way to do it will be to divide publish task into two separate tasks and use depends, mustRunAfter to control execution order. Look at this example:
task publishInit << {
println '(1)'
}
task aoeu << {
println '(2)'
}
task publish << {
println '(3)'
}
publish.dependsOn publishInit
publish.dependsOn aoeu
aoeu.mustRunAfter publishInit
It will return
C:\>gradle publish
:publishInit
(1)
:aoeu
(2)
:publish
(3)
task snth << {
println "************************* before"
}
task aoeu << {
println "**************************** during aoeu"
}
publish.dependsOn(aoeu)
task ueoa << {
println "**************************** during ueoa"
}
publish.dependsOn(ueoa)
publish.doLast {
println "************************* after"
}
publish.dependsOn.each { dependency ->
if (dependency instanceof Task) {
dependency.dependsOn(snth)
}
}
will output:
:snth
************************* before
:aoeu
**************************** during aoeu
:ueoa
**************************** during ueoa
:publish
************************* after
If you want the dependency added recursively:
def recursivelyAddDependsOn(Task parent, Task dependsOn) {
if (!parent.equals(dependsOn)) {
parent.dependsOn(dependsOn)
def tasks = parent.dependsOn.findAll { dependency ->
dependency instanceof Task
}
tasks.each { task ->
recursivelyAddDependsOn(task, dependsOn)
}
}
}
recursivelyAddDependsOn(publish, snth)
And a more functional solution is:
def recursivelyApplyToTaskDependencies(Task parent, Closure closure) {
closure(parent)
parent.dependsOn.findAll { dependency ->
dependency instanceof Task
}.each { task ->
recursivelyApplyToTaskDependencies(task, closure)
}
}
def recursivelyAddTaskDependency(Task parent, Task dependency) {
def addTaskDependency = { p ->
if (!p.name.equals(dependency.name)) {
p.dependsOn(dependency)
}
}
recursivelyApplyToTaskDependencies(parent, addTaskDependency)
}
recursivelyAddTaskDependency(publish, snth)
Ordering tasks is headache, and << is deprecated syntax.
I ended up to weave tasks as below.
task publish {
println "here we go"
}
task task1 {
println "first"
}
task task2 {
println "second"
}
task task3 {
println "third"
}
// task execution order. this executes bottom to top order.
publish.dependsOn task3
task3.dependsOn task2
task2.dependsOn task1
The publish task result is as below;
here we go
first
second
third