Gradle task can be defined in root but not in child - gradle

I have a gradle sync task:
task updateSharedCode {
group = 'build'
}
updateSharedCode << {
sync {
from '../employee_shared/src'
into 'src/shared'
}
}
If I paste this task in the root's subprojects object everything runs fine But I only want to run this on a small subsection of my subprojects. But when I copy this task into one of the subprojects and remove it from the root I get the error
Execution failed for task ':employee_app:updateSharedCode'.
Could not find method from() for arguments [../employee_shared/src] on project ':employee_app'.
I have no clue why this is happening so any help would be helpfull.

Related

Gradle- Copy Dependencies of Sub Projects into respective folder of Sub Projects

From root, I am basically trying to fetch the dependencies of each sub project and copy into a directory named dependency within each subproject
I have a root Project and in that build.gradle file i have a task like below:
task copyDependencies(type:Copy) {
nonTestProjects.each {
delete rootProject.project(it).file('dependencies')
from rootProject.project(it).configurations.runtime
intorootProject.project(it).file('dependencies/')
}
}
Inside the Sub Projects build.gradle, i have dependencies as below:
dependencies
{
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
implementation "io.netty:netty:$nettyVersion"
implementation "xmlpull:xmlpull:$xmlPullVersion"
}
On running the task copydependencies from root, i am getting error as below:
Could not get unknown property 'runtime' for configuration container of type org.gradle.api.internal.artifacts.configurations.DefaultConfig
urationContainer.
You get the error Could not get unknown property 'runtime' for configuration container because when gradle configures your root project and tries to create the task copyDependencies, the subprojects have not yet been evaluated, so Gradle doesn't know about "runtime" configuration at this stage ( java plugin has not yet been applied to subprojects).
So one solution would be to wrap this task creation into a gradle.projectsEvaluated lifecycle hook:
gradle.projectsEvaluated {
task copyDependencies(type:Copy) {
// task definition ...
}
}
But then you will have other issues because you want to copy different sources to different destination directories (see How to copy to multiple destinations with Gradle copy task? for possible solution to this issue)
I think a better way would be to create different copyDependencies tasks, one per subproject , and create an "aggregator" task in root project which will depend on these subprojects's tasks:
// aggregator task at root project level
task copyDependencies
// create copydependencies task for each (non-test) subproject
gradle.projectsEvaluated {
nonTestProjects.each {
Project proj = project(it)
Task task = proj.task('copyDependencies', type: Copy) {
from proj.configurations.runtimeClasspath
into proj.file("dependencies")
doFirst {
file('dependencies').deleteDir()
}
}
copyDependencies.dependsOn task
}
}

Depend on multiple gradle tasks in multi project build

Currently I have task which starts Google Cloud server, runs tests and stops server. It is defined at root project:
buildscript {...}
allprojects {...}
task startServer (dependsOn: "backend:appengineStart") {}
task testPaid (dependsOn: "app:connectedPaidDebugAndroidTest") {}
task stopServer (dependsOn: "backend:appengineStop") {}
task GCEtesting {
dependsOn = ["startServer",
"testPaid",
"stopServer"]
group = 'custom'
description 'Starts GCE server, runs tests and stops server.'
testPaid.mustRunAfter 'startServer'
stopServer.mustRunAfter 'testPaid'
}
I tried multiple ways to write it something like this, short with only one task. I didn't get how to refer to task from another project and call mustRunAfter on it. This doesn't work (I also tried to refer from Project.tasks.getByPath, root.tasks, etc):
task GCEtesting {
dependsOn = ["backend:appengineStart",
"app:connectedPaidDebugAndroidTest",
"backend:appengineStop"]
group = 'custom'
description 'Starts GCE server, runs tests and stops server.'
"app:connectedPaidDebugAndroidTest".mustRunAfter "backend:appengineStart"
"backend:appengineStop".mustRunAfter "app:connectedPaidDebugAndroidTest"
}
Is it possible? What is correct syntax to make this work?
It looks like your problem is that you're treating dependsOn as meaning "invoke this task". It actually means "ensure the result of the depended on task is available before the dependent task starts". That's why your first solution didn't work: statements like testPaid.mustRunAfter only affect the actions of the testPaid task itself, not its dependencies.
Anyway, you can get the behaviour you want using dependsOn and finalizedBy, but they have to be declared in the build file of the app subproject.
app/build.gradle:
task connectedPaidDebugAndroidTest {
//
//...
//
dependsOn 'backend:appengineStart' // Ensure appengineStart is run at some point before this task
finalizedBy 'backend:appendginStop' // Ensure appengineStop is run at some point after this task
}
Then, you can run your tests simply with gradle app:connectedPaidDebugAndroidTest. If you really want to define a task in the root project to run the tests, then that's easy too:
build.gradle:
task GCEtesting {
dependsOn = "app:connectedPaidDebugAndroidTest"
}

How to call a Gradle subproject’s task from a Gradle test?

I have a project that includes a subproject like so:
Root Project
|----gradle.build
|----SubProject
|----|----gradle.build
The SubProject here contains a copy script that I need called when the root project’s test command is called.
So I have attempted to call the SubProject’s task in the Root project like this:
Task myTest(type: Test) {
Project(‘:SubProject’).tasks.myCopyTask.execut()
}
However, this results in an error, “Could not get unknown property ‘myCopyTask’ for task set.”
Do you know how this call should be done, and what the proper syntax should be?
There a multiple things not working in your example:
You should never call execute on tasks! NEVER! Tasks are called by Gradles task system automatically and calling execute may break this system.
The closure ({ }) you use when creating a task is for configuration. It is not executed when the task gets executed, but when it is created.
Subprojects in Gradle are created and evaluated after the root project is created and evaluated. So tasks from subprojects do not even exist when the root project gets evaluated.
You can solve all these problems by using the dependsOn method with absolute task paths:
task myTest (type: Test) {
dependsOn ':Subproject:myCopyTask'
}

Gradle task not executed if added as a dependency

I have two gradle tasks in my build.gradle file, one to archive a folder and another to push it to a remote server.
task tarTask(type: Exec) {
commandLine 'tar', '-czf', 'javadocs.tgz', 'javadocs/'
}
If I execute tarTask alone with gradle tarTask and with the publish task commented out, the build succeeds.
I am using this task as a dependency in the publish task.
task publish(dependsOn: tarTask) {
ssh.run {
settings {
knownHosts = allowAnyHosts
fileTransfer = 'scp'
}
session(remotes.webServer) {
from: 'javadocs.tgz', into: 'publishingHouse/'
}
}
}
But when i execute gradle publish it fails saying that it is not able to find the tgz file which should have been created if the previous task is executed.
java.io.FileNotFoundException: javadocs.tgz
Being new to gradle i am not really sure what I am missing here. Any ideas on what I can do?
I suppose the reason is within the phase when tasks are executed. tarTask is configured at the configuration phase and will be executed at the execution phase.
And at the same time publish task doesn't have any behavior to execute at the execution phase, but has ssh.run to be executed during configuration.
This mean, that when you run gradle publish your logic to copy tar-archive is executed at the configuration phase, while tar-archive is not yet exists (it will be created later at the execution phase).
To make a copy execution at the execution phase you can simply add << to the publish task declaration as follows:
task publish(dependsOn: tarTask) << {
ssh.run {
settings {
knownHosts = allowAnyHosts
fileTransfer = 'scp'
}
session(remotes.webServer) {
from: 'javadocs.tgz', into: 'publishingHouse/'
}
}
}
Note, that << is the same as doLast and the closure will be excuted at the execution phase. You can read about Gradle build lifecycle here

How to execute another task from a task with dependencies

I have multiple gradle files to run test suites. Each gradle file has multiple tasks with dependencies defined. And there will be a task with same name as file name to run all those tasks.
Example
foo_test.gradle
task testBlockA << {
// do some tests here
}
task testBlockB(dependsOn: testBlockC) << {
// do some tests here
}
task testBlockC << {
// do some stuff here
}
task foo_test(dependsOn: testBlockA, testBlockB)
Now I want to write a common test.gradle file which, based on argument provided, loads the given test gradle file and runs the task
gradle -b test.gradle -Ptest_to_run=foo_test
How to I create a task in test.gradle, which will run foo_test task of foo_test.gradle, along with its dependencies (testBlockA-C)
As I read tasks['foo_test'].execute() will not work as it does not execute the dependsOn tasks.
In your main build.gradle file, you can read the provided -P attribute in your build.gradle file:
if(project.hasProperty("test_to_run")){
apply from:test_to_run
defaultTasks test_to_run
}
this snippet applies a buildscript based on the input property and also declares a defaultTask to run.

Resources