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?
Related
I have three Gradle tasks if I execute them one by one on its own then its working. But when I execute them from another task then its not working. Here is how my task looks like
import com.github.gradle.node.npm.task.NpmTask
plugins {
id("com.github.node-gradle.node") version "3.4.0"
}
// Executing this task on its own is working
tasks.register<NpmTask>("buildFrontEnd") {
workingDir.set(file("${projectDir}/frontend"))
args.set(listOf("run", "build"))
}
// Executing this task on its own is working
tasks.register<Delete>("cleanFrontEnd") {
delete(
fileTree("${projectDir}/backend/main/resources/static/js"),
)
}
// Executing this task on its own is working
tasks.register<Copy>("copyFrontEnd") {
into("$projectDir")
copy {
from("${projectDir}/frontend/dist/css")
into("${projectDir}/backend/main/resources/static/css")
}
copy {
from("${projectDir}/frontend/dist/js")
into("${projectDir}/backend/main/resources/static/js")
}
}
// This tasks is not executing "copyFrontEnd"
tasks.register("frontEndBuild") {
dependsOn("buildFrontEnd", "cleanFrontEnd", "copyFrontEnd")
tasks.findByName("copyFrontEnd")?.mustRunAfter("buildFrontEnd", "cleanFrontEnd")
// Tried this too but it is not working
// tasks.findByName("cleanFrontEnd")?.mustRunAfter("buildFrontEnd")
// tasks.findByName("copyFrontEnd")?.mustRunAfter("cleanFrontEnd")
}
This is the output
> Task :cleanFrontEnd
> Task :copyFrontEnd NO-SOURCE
> Task :frontEndBuild
BUILD SUCCESSFUL in 20s
2 actionable tasks: 2 executed
For :copyFrontEnd it is saying NO-SOURCE but if that is the case then why its working when executing on its own? Is there anyway to fix this.
When you register a task, the bit inside the { } block configures the task. This block will always run whenever the task is required.
tasks.register<Copy>("copyFrontEnd") {
into("$projectDir")
// these copy actions will ALWAYS run whenever Gradle configures this task
copy {
from("${projectDir}/frontend/dist/css")
into("${projectDir}/backend/main/resources/static/css")
}
copy {
from("${projectDir}/frontend/dist/js")
into("${projectDir}/backend/main/resources/static/js")
}
}
Because you've used register when creating the task, Gradle won't execute the task configuration block won't unless the task is required. But when it is, those copy actions will run immediately.
To add task actions, which will actually do the work of the task, add them using doLast { } or doFirst { }.
tasks.register<Copy>("copyFrontEnd") {
into("$projectDir")
doLast {
copy {
from("${projectDir}/frontend/dist/css")
into("${projectDir}/backend/main/resources/static/css")
}
copy {
from("${projectDir}/frontend/dist/js")
into("${projectDir}/backend/main/resources/static/js")
}
}
}
Now those copy actions will only run when the task runs.
This still won't work however...
NO-SOURCE
Task did not need to execute its actions.
Task has inputs and outputs, but no sources
https://docs.gradle.org/current/userguide/more_about_tasks.html#sec:task_outcomes
When you register a Copy task, you need to specify what the source is.
tasks.register<Copy>("copyFrontEnd") {
into("$projectDir")
// from(...) // no from, no source - Gradle thinks "this task doesn't need to run"
}
In your case, you can specify the source as "${projectDir}/frontend/dist/css" and get rid of the two separate copy actions.
tasks.register<Copy>("copyFrontEnd") {
from("${projectDir}/frontend/dist/")
into("${projectDir}/backend/main/resources/static/css")
}
You might want to fiddle around with includes to only copy the css/ and js/ directories - https://docs.gradle.org/current/userguide/working_with_files.html#sec:copying_directories_example
Typesafe references
This last bit is unrelated, but I thought I'd include it as it can help make your buildscript clearer.
While you can reference task by their names, it's nicer to reference them by a variable. When you register a task, it returns a handle to that task.
You can use that handle to specify task dependencies.
val buildFrontEndTask: TaskProvider<NpmTask> = tasks.register<NpmTask>("buildFrontEnd") {
// ...
}
val cleanFrontEndTask: TaskProvider<Delete> = tasks.register<Delete>("cleanFrontEnd") {
// ...
}
val copyFrontEndTask: TaskProvider<Copy> = tasks.register<Copy>("copyFrontEnd") {
// ...
}
tasks.register("frontEndBuild") {
// here you can set the task dependencies based on the task providers
dependsOn(buildFrontEndTask, cleanFrontEndTask, copyFrontEndTask)
}
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 am working with a build.gradle file that has multiple ways to specify executions for a task - setup. To call a task from another gradle file - runtests.gradle, I created a task - testTask and added task dependency using dependsOn, but this implementation does not seem to work and giving out an error like :
Could not find property 'testTask' on root project 'GradleFile
My build file looks like this :
build.gradle
task setup(dependsOn: testTask) <<
{
println "In main execution"
}
// new task
task testTask(type: GradleBuild) {
if (getEnvironmentVariable('RUN_TEST').equalsIgnoreCase("true")) {
buildFile = "../Behave/runtests.gradle"
tasks = ['mainTask']
}
else {
println "Exiting runTests Task"
}
}
setup.doFirst {
println "In first execution"
}
setup.doLast {
println "In last execution"
}
D:\>gradle -q GradleFile/build.gradle setup
I am not looking to make much changes to existing tasks, so is there any other workaround I should try?
I have been through many links but could not find anything that suits this scenario. Looking for suggestions please.
Gradle is sensitive to the ordering of tasks in the build script if a task instance is given in the dependsOn. The task setup depends on task (instance) testTask which, at the moment the build script is compiled, doesn't exist yet. The most common options to solve the issue are:
Define task setup below testTask:
task testTask(type: GradleBuild) {
}
task setup(dependsOn: testTask) {
}
Use a relative path to the task, i.e. the task's name, in the dependsOn
task setup(dependsOn: 'testTask') {
}
task testTask(type: GradleBuild) {
}
Please find more details in Javadoc of Task.
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 want execute some command from command line in gradle task(e.g. print all files in dir):
task dir(type: Exec) {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
doLast {
println ("result = " + standardOutput)
}
}
It's work. OK. But when I put it on onLast section it's not work:
task dir(type: Exec) {
doLast {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
println ("result = " + standardOutput)
}
}
I get error:
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':app:dir'.
execCommand == null!
The reason is in the fact, that task of Exec should be configured during configuration phase of the build, otherwise your task will be not configured and fail.
In you first example everything works due to configuration happens at the configuratyion phase. Your second example tries to configure the task within doLast closure - right after the task is executed yet.
If you really need to execute something in doLast, you can use something like this, without creating special task:
task someTaskName {
doLast {
exec {
commandLine adbCommand
}
}
}
Here is exec-specification used to execute some command and it's configured and executed at the same time.