Gradle onlyIf condition for task is not working - gradle

I'm trying trying to run a gradle task only when an environment Variable is set. I found this onlyIf function in https://discuss.gradle.org/t/how-do-i-run-a-task-only-if-an-environment-variable-is-defined/12438
So I wrote this
task onlyRunIfItIsCI() {
println System.env['CI']
onlyIf {
System.env['CI'] == "true"
}
}
However, regardless of if I set the CI or not, it still got run. Did I miss anything?

Apparently in Gradle, it has 2 pass of execution, first is configuration, and second is execution.
The configuration will be run regardless of the onlyIf. To ensure the onlyIf is in effect, we should wrap the common execution under the gradle specific scope e.g. doFirst or doLast
task onlyRunIfItIsCI() {
doFirst {
println System.env['CI']
}
doLast {
println System.env['CI']
}
onlyIf {
System.env['CI'] == "true"
}
}
clean.dependsOn onlyRunIfItIsCI
Do note, we need to have it dependsOn, for the actual execution.
Another example is where the from and into is gradle specific command where will not run during configuration.
task copyPreCommitToGitHook(type: Copy) {
from new File(rootProject.rootDir, 'storage/pre-commit')
into { new File(rootProject.rootDir, '.git/hooks') }
onlyIf {
System.env['CI'] == null
}
}
tasks.getByPath(':app:preBuild').dependsOn copyPreCommitToGitHook

Related

How to run certain task with gradle

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.

Creating a task that runs before all other tasks in gradle

I need to create an initialize task that will run before all other task when I execute it.
task A {
println "Task A"
}
task initializer {
println "initialized"
}
If I execute gradle -q A, the output will be:
>initialized
>Task A
Now if i'll add:
task B {
println "Task B"
}
Execute gradle -q B, and I get:
>initialized
>Task B
So it doesn't matter which task I execute, it always get "initialized" first.
You can make every Task who's name is NOT 'initializer' depend on the 'initializer' task. Eg:
task initializer {
doLast { println "initializer" }
}
task task1() {
doLast { println "task1" }
}
// make every other task depend on 'initializer'
// matching() and all() are "live" so any tasks declared after this line will also depend on 'initializer'
tasks.matching { it.name != 'initializer' }.all { Task task ->
task.dependsOn initializer
}
task task2() {
doLast { println "task2" }
}
Or you could add a BuildListener (or use one of the convenience methods eg: Gradle.buildStarted(...))
Seems like you aim execution phase, and you want a task precursing each task or just run as a first task in the execution phase?
If you want a task to always execute in every project before each other task after its being evaluated you can add a closure to he main build.gradle:
allprojects {
afterEvaluate {
for(def task in it.tasks)
if(task != rootProject.tasks.YourTask)
task.dependsOn rootProject.tasks.YourTask
}
}
or
tasks.matching {it != YourTask}.all {it.dependsOn YourTask}
You can also use the Task Execution Graph to define the lifecycle. There are few ways of achieving your goal, depending on your needs and a project structure.
The previously suggested solution with dependsOn works fine, but I don't like about it that it changes and clutters the task dependencies. The first solution coming to my mind is using Gradle Initialization Scripts. They are really cool. But, the usage is a bit tedious: currently there is no way to have a default project-local Gradle init script. You have to either explicitly specify the script(s) on command line, or place them in USER_HOME/GRADLE_HOME.
So another solution (already briefliy mentioned by #lance-java) which can be used to run some initialization, like a init task/script, is "build listeners". Depending on how early/late the initialization code should run, I use one of these two:
gradle.afterProject {
println '=== initialized in afterProject'
}
or
gradle.taskGraph.whenReady {
println '=== initialized in taskGraph.whenReady'
}
Here the docs of the Gradle interface and of BuildListener.
Note that some of the events occur very early, and you probably can't use them because of that, like e.g. beforeProject and buildStarted (explanations here and there).

Gradle Task dependencies Execution issue

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
}

gradle tasks -all throwing error

I have test build.gradle file as follows
task someTask(type: Sync) {
def folder = new File('fold1/fold2/');
if(!folder.exists()) {
throw new GradleException('Folder Absent');
}
else {
}
}
When I do gradle tasks --all it is running the task and throwing exception. I was thinking that only when this task is run that it will check for folder but it is actually running it for any task I run.
Can someone suggest workaround for this?
Thanks in advance.
Your code is executed during the configuration phase and not during the execution phase. You need to put it in a doFirst or doLast block:
task someTask(type: Sync) {
doLast {
def folder = new File('fold1/fold2/');
if (!folder.exists()) {
throw new GradleException('Folder Absent');
}
else {
}
}
}
See also: Why is my Gradle task always running?

Gradle - How to set dependency tasks for Exec-type tasks?

Say, you have following task:
task commandA() {
doLast {
project.ext.ping = 'PING'
}
}
This will work:
task commandB() {
dependsOn commandA
doLast {
println ping
}
}
This will fail:
task commandC(type: Exec) {
dependsOn commandA
commandLine "echo", ping
}
With Could not find property 'ping' on task 'commandC'. error message.
So, how one can declare dependency for an exec-type task and set some variable in that dependency?
Just don't initialize the variable within the doLast block, since it's getting initialized at the execution phase, but commandLine "echo", ping is trying to get it at the configuration phase of the build.
So, you need something like that:
task commandA() {
project.ext.ping = 'PING'
}
Or even without task, as follows:
project.ext.ping = 'PING'
Because configuration of any task is always executed, even if the task's action won't be executed.
Another solution is to use exec-action, not exec-task, something like this:
task commandA() {
doLast {
project.ext.ping = 'PING'
}
}
task commandC {
dependsOn commandA
doLast {
exec {
commandLine ping, "192.168.100.1"
}
}
}
In this case, exec-closure will be done during execution phase wuth the ping variable already available.
You can read about build lifecycle in the official Gradle user guide

Resources