Run grade tasks inside a task without dependsOn - android

Assume that I have set of tasks executed from the cmd line and it works:
gradle processReleaseManifest compileReleaseSources run assembleRelease
Here run is the task which I Defined.
So My requirement is that I need to create a task which executes the above mentioned 4 tasks,
like say new task abc, runs the above mentioned tasks in the same order,
I know I cannot use dependsOn in this case because,processReleaseManifest compileReleaseSource when used in the build gradle it shows,
Could not get unknown property 'assembleRelease' for project ':app' of type org.gradle.api.Project.
So what is the solution?

You can, as #lu.koerfer's answer indicates use strings in the dependsOn list to refer to tasks that are defined further down in the build file.
In other words, this works:
task foo {}
task bar(dependsOn: [foo]) {}
and this also works:
task bar(dependsOn: ['foo']) {}
task foo {}
Now as for getting the tasks to run in the order you want things are not quite as straight forward. The dependsOn property only tells the task which tasks need to run before the task itself runs. It does not tell gradle to run the tasks in the order defined in the dependsOn clause.
An example:
task one {}
task two {}
task three {}
task run(dependsOn: [one, two, three]) {}
results in the following output when run:
~> gradle run
:one UP-TO-DATE
:three UP-TO-DATE
:two UP-TO-DATE
:run UP-TO-DATE
BUILD SUCCESSFUL
...note the fact that we are not running in the order one, two, three, run.
In other words, the command line invocation forces the tasks to run in the order defined whereas the dependsOn is a set and has no ordering.
There are a few ways you can get the tasks to run in the order you want. One is to define dependencies on the tasks (this is probably the common path):
task one {}
task two(dependsOn: ['one']) {}
task three(dependsOn: ['two']) {}
task run(dependsOn: [one, two, three]) {}
which results in:
~> gradle run
:one UP-TO-DATE
:two UP-TO-DATE
:three UP-TO-DATE
:run UP-TO-DATE
BUILD SUCCESSFUL
another is to use the task ordering constructs added in later versions of gradle.
Also, if you need to add a task dependency to a task which was defined somewhere earlier in the file, you can do so via:
task foo {}
someTaskDefinedFurtherUp.dependsOn 'foo'
which adds the task foo to the dependencies of someTaskDefinedFurtherUp.

You need to pass the task names as strings to the dependsOn method, because at the time you call it, the task objects haven't been created yet. However, if you pass strings, the task names will be evaluated later:
task abc {
dependsOn 'processReleaseManifest', 'compileReleaseSources', 'run', 'assembleRelease'
}

As it may be possible but very complicated to specify the task dependencies and ordering via dependsOn and mustRunAfter / shouldRunAfter, I'll propose another possible solution:
You can invoke Gradle from Gradle and specify the tasks in same way you would via command line:
task abc(type: GradleBuild) {
tasks = ['processReleaseManifest', 'compileReleaseSources', 'run', 'assembleRelease']
}
This will call Gradle again from the current build and execute the tasks in the specified order.

Related

Android Gradle - how to run task after app installation

I need to copy some files to the Android App folder (data/data/...) after installing the app via Gradle. This has to be done at every debug build before the app gets started and thus I assumed I could find a gradle task that could be executed after the installation (but before the run command).
It works somewhat fine for other tasks when doing something like
tasks.whenTaskAdded { task ->
if (task.name == 'build') {
task.dependsOn taskXYZ
}
}
They then get executed before my build task is executed.
However, since I need that to happen after the install process (and before the running of the app) I was hoping for something like this:
tasks.whenTaskAdded { task ->
if (task.name.startsWith('install')){
println ">>>>>>>>> " + task.name
task.finalizedBy taskXYZ
}
But sadly, this does not work.
In the build output I can see that this executed pretty much at the start.
Executing tasks: [:app:assemblePlayStoreStagingDebug] in project /Users/...
> Configure project :app
###########################
TASK XYZ WAS EXECUTED HERE!
###########################
---> installPlayStoreStagingDebug
> Task :app:preBuild UP-TO-DATE
> Task :app:prePlayStoreStagingDebugBuild
> Task :app:compilePlayStoreStagingDebugAidl UP-TO-DATE
...
> Task :app:stripPlayStoreStagingDebugDebugSymbols UP-TO-DATE
> Task :app:packagePlayStoreStagingDebug
> Task :app:assemblePlayStoreStagingDebug
BUILD SUCCESSFUL in 6s
33 actionable tasks: 6 executed, 27 up-to-date
It looks like the task did not get executed at the expected time. What I need is something like this:
Task Build
Task Install
Task XYZ
Task run App
But how can I achieve this?
Solutions like this one
Android run Gradle task after app install
Don't seem to work for the install task.
----- EDIT -----
I tried it the other way around and - instead of using gradle tasks - I tried to change the run configuration of AS by adding an "external tool" call in the "before launch" settings.
https://developer.android.com/studio/run/rundebugconfig#definingbefore
However, when selecting for instance a shell script there, it won't get executed (for instance I was creating a file or directory in that script so I could see whether it was executed at all). It doesn't seem to be that error=13 permission problem. So if gradle tasks are not a solution, perhaps anyone knows a solution with this option!
In gradle you can use the mustRunAfter task, this does not create dependencies between the tasks but forces one task to be after a list of other tasks in the build sequence.
An example:
task taskY {
mustRunAfter "taskX"
}
https://gradle.github.io/kotlin-dsl-docs/api/org.gradle.api/-task/must-run-after.html

Execute android build tasks in custom tasks

I wanted to remove the project makefile and write some nice gradle tasks.
I need to execute the following tasks, in this order:
Clean
Increment version
Build
Upload
#1, #3 and #4 are tasks from android and plugin (bintray) while #2 is a custom task. Here is what I have so far:
task releaseMajor {
doLast {
clean.execute()
build.execute()
incrementVersion.execute()
bintrayUpload.execute()
}
}
The run order was not so great as I think clean was run after build. And binrayUpload was running without flavor (release). I've also tried to use dependsOn without success (order not working).
I couldn't find in Gradle doc how to do this properly. When execute in the right order, from CLI, everything works perfectly.
Use mustRunAfter, or finalizedBy for finer order control:
task releaseMajor (dependsOn: ['clean', 'build', 'incrementVersion', 'bintrayUpload'])
build.mustRunAfter clean
incrementVersion.mustRunAfter build
bintrayUpload.mustRunAfter incrementVersion
Tried this
task clean {
println 'clean task executing'
}
task incrementVersion (dependsOn:"clean"){
println 'incrementVersion task executing'
}
task building (dependsOn:"incrementVersion"){
println 'build task executing'
}
task bintrayUpload (dependsOn:"building") {
println 'bintrayUpload task executing'
}
The output was
clean task executing
incrementVersion task executing
build task executing
bintrayUpload task executing
and executed ./gradlew bintryUpload

Want to run a custom gradle task only when running Unit test

How to set up gradle to run a particular custom copy task, only when running unit tests?
EDIT
I want to run these tasks when i press build, i. e only in the flavor of the build with unit test execution included.
I've finally found the solution, with the help of this documentation which presents all the tasks that run during build, test, release etc. in a very concise manner. So by making tasks clean, preBuild depend on my copyTask I can ensure that the copy task is run every time the project is cleaned or built.
But since I don't want to run this during building or cleaning process but want to run it when I only run tests, I identified a task that compiles release unit test sources called the compileReleaseUnitTestSources but just mentioning it in build.gradle as
compileReleaseUnitTestSources.dependsOn(myCopyTask)
doesn't actually work, because gradle will give an error saying it cannot find the task compileReleaseUnitTestSources as for some reason that task is not available yet. Instead by enclosing it in a afterEvaluate block we can ensure that this block is executed after all tasks are evaluated, that way we have access to that task now, So finally I added this to my build.gradle
afterEvaluate {
compileReleaseUnitTestSources.dependsOn(copyResDirectoryToClasses)
}
All the answers here mention to use the dependsOn keyword to attach my task to another task that is run during general build/test execution, but none of them mentioned how to go around the problem where gradle is not able to find the tasks even though you know for sure that these tasks were available and run during build/test execution.
you have to set up a "customCopyTask" and make the "test-task" which does the unittests depend on the "customCopyTask" like this
task customCopyTask(type: Copy) {
from sourceSets.test.resources
into sourceSets.test.output.classesDir
}
test.dependsOn customCopyTask
You can make some task finalizing another, in that case this task will run only if another one was called, right after it. This could be done as:
task runUnitTest << {
println 'running tests'
}
task copyTestResults << {
println 'copying results'
}
//make copyTestResults finalize runUnitTest
runUnitTest.finalizedBy copyTestResults
You can read about it in the official user guide.
Additionally, if your unit test could be up-to-date and you don't want to run you copy task in that case, you can check the test task status and skip copy-task, as:
task copyTestResults {
doFirst {
//chtck anothe task status and skip this one if it didn't actually work
if (!tasks.getByName("runUnitTest").getState().didWork) {
throw new StopExecutionException();
}
}
doLast{
println 'copying results'
}
}
Or, if you just need to run copy-task before unit tests, make the test task depending on copy-task by setting it's dependsOn property, read about it with a number og examples here

Gradle Copy Task is always Up To Date

My gradle task looks like this
task xml_file_to_vs_build(type: Copy) {
outputs.upToDateWhen { false }
doLast {
outputs.upToDateWhen { false }
println("copying strings.xml");
from 'src/main/res/values'
into '../vso_build'
include 'strings.xml'
}
}
The task is always up to date . If I put the block in the configuration phase i.e. out of doLast, everything works fine. But then the code executed even if I execute gradlew Tasks which I do not want. What am I doing wrong ?
A Copy task only gets executed if it has something to copy. Telling it what to copy is part of configuring the task, and therefore needs to be done in the configuration phase, rather than the execution phase. These are very important concepts to understand, and you can read up on them in the Gradle User Guide or on the Gradle Forums.
doFirst and doLast blocks get executed in the execution phase, as part of executing the task. Both are too late to tell the task what to copy: doFirst gets executed immediately before the main task action (which in this case is the copying), but (shortly) after the skipped and up-to-date checks (which are based on the task's configuration). doLast gets executed after the main task action, and is therefore clearly too late.
You should define the task in the following way:
task xml_file_to_vs_build(type: Copy) {
println("copying strings.xml")
from 'src/main/res/values'
into '../vso_build'
include 'strings.xml'
}

How to call android flavor gradle task from another task

In my project I have 3 product flavors (dev, production and testing). I've recently switched from Ant, so maybe I still have Ant mindset, but this is what I am trying to achieve:
create custom task (let's call it "buildAndUpload"), which will call assembleDevRelease and then call another task.
Here is what I've tried:
task myCustomTask {
println "My Custom Task"
}
task buildAndUpload {
tasks.assembleDevRelease.execute()
tasks.myCustomTask.execute()
}
When I call buildAndUpload task (gradlew buildAndUpload) I am getting following output:
:buildAndUpload
"My Custom Task"
As you can see assembleDevRelease task is not called. I know that I can use doLast closure, but I really want to have myCustomTask call contained in separate task.
A task cannot call another task, but it can depend on it. For example:
task myCustomTask {
dependsOn "assembleDevRelease"
doLast {
println "executing..."
}
}
You should set the two tasks as dependencies. You'll want to do something along the lines of
task buildAndUpload(dependsOn: ['assembleDevRelease', 'myCustomTask'] {
}
Also please refer to the Gradle documentation on the build lifecycle for more details on execution order:
http://www.gradle.org/docs/current/userguide/build_lifecycle.html

Categories

Resources