Gradle Custom Task With Input - android

I have to create a gradle custom task in KOTLIN with different args as input.
So based on the args, the custom task should run other tasks.
e.g: I want to run:
./gradlew ci type=release distribution=true version=1.2.2
OR
./gradlew ci type=debug distribution=true version=1.2.2
This command should run tasks: clean, assembleRelease OR assembleDebug (based on type param) and also another task to distribute the artifact (already have this one) if the distribute param is true.
Question 1: Is there any way to create a custom task that runs other tasks based on external params?
Question 2: Is there any way to inject the args? (the above commands are not valid I think)

You can pass properties with -P command and here is an example.
task passP() {
if (customProp.equals("myProp")) {
println customProp
}
}
this will only print if you execute the following command Gradle -PcustomProp=myProp passP
Now that you can pass parameters, You can clean, assembleRelease OR assembleDebug according to the passed parameters.
There Are two ways you can achieve that.
First way :
Make a gradle custome task to execute another gradle command which do not look neat. but the code will look like this
task passP(type: Exec) {
commandLine("cmd", "/c")
if (customProp.equals("clean")) {
args "gradle clean"
}
}
This will execute a normal clean if you passed clean as a parameter.
The second way :
You would be using finializeBy keyword
You can call the 3 tasks according to the passed parameters.
The code will be something like this (not tested) :
task passP() {
if (customProp.equals("clean")) {
tasks.named("clean") { finalizedBy("passP") }
if (customProp.equals("debug")) {
tasks.named("assembleDebug ") { finalizedBy("passP") }
}
}
The first way work 100%, But am not sure about the second one, As am only used to use finalizedBy out side of the custom task scope.

Related

Best way to add a code generation step in the build process?

I have a python script that modifies a part of a java class (add static fields) according to another file.
What is the best way to add it in the Gradle build process (My script requires pyton3 (so it would be better to tell the user if he doesn't have it) and need to be executed before the java compilation) ?
I'm not certain what the best way to run python from gradle is, but one candidate is to use the exec task:
task runPython(type:Exec) {
workingDir 'path_to_script'
commandLine /*'cmd', '/c'*/ 'python', 'my_script.py'
}
You might have to add cmd and /c on windows. You can also parse/assert on stdout for success conditions. See here for more about Exec.
As for ensuring that this task always runs before compileJava, you have to add this task as a dependsOn for the compileJava task:
compileJava.dependsOn runPython
alternate syntax:
compileJava{
dependsOn runPython
}
When compileJava dependsOn runPython, runPython is executed first everytime compileJava is invoked.

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

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

How to change Gradle install tasks

I want to edit gradle task named installDebug. Where is the task (or script) located? Maybe this script is located in binary code and I'm not change that?
Really, I want run edit something option for adb.
Example: My task must contain:
Run adb like "adb connect 192.168.1.2:5555"
Run "debugInstall" gradles task, directly.
Do something, like - adb then open apk on my adb server..
What I should do:
Edit debugTask if possible?
Or edit build.grade and make own task script?
All the tasks are located in build.gradle script itself or in the plugin that is applied at the beginning of the script.
installDebug task is provided by as far as I remember android plugin. Every single task consists of actions that are executed sequentially. Here's the place to start.
You can extend a task adding action to the beginning of at the end of internal actions list.
So:
//this piece of code will run *adb connect* in the background
installDebug.doFirst {
def processBuilder = new ProcessBuilder(['adb', 'connnect', '192.168.1.2:5555'])
processBuilder.start()
}
installDebug.doLast {
//Do something, like - adb then open apk on my adb server..
}
Here, two actions were added to installDebug task. If you run gradle installDebug, first action will be run, then the task itself and finally the second action that is defined. That's all in general.
You can add a task to your build.gradle, and call it in command line.
This is what I have done :
task adbConnect(type: Exec) {
commandLine 'adb', 'connect', '192.168.200.92'
}
then I call gradle adbConnect connectedCheck, but you can use gradle adbConnect debugInstall

gradle custom task order on Android

I have 2 gradle tasks that i want to run after assembleRelease task.
task copyRequiredFilesToVersionControl(type:Copy) {
...
}
task ('versionControl') << {
...
}
If I configure order for these tasks as below tasks get never called...
copyRequiredFilesToVersionControl.dependsOn(assembleRelease)
versionControl.dependsOn(copyRequiredFilesToVersionControl)
If i change order like;
assembleRelease.dependsOn(copyRequiredFilesToVersionControl)
versionControl.dependsOn(copyRequiredFilesToVersionControl)
Tasks are run at the beginning of document. So there is no file to copy and add to version control.
What is the best approach?
I have found method that called doLast. So i fixed my problem with it.
assembleRelease {
doLast {
tasks.versionControl.execute()
}
}
The best approach that I've found to date, has been to use the Ordering Tasks feature in Gradle : see http://www.gradle.org/docs/current/userguide/more_about_tasks.html for more documentation, currently section 15.5.
Basically, you have two rules available : MUST run after and SHOULD run after. I like the rule quite a bit, I use this to create zip archives of projects automatically. NOTE : you must still make use of the "dependsOn" to get proper execution if tasks that you need to have run in a particular order.

Categories

Resources