I'm using Gradle and I try to configure for my Android project. I read document and I see that there are two ways of defining a task.
Without << Operator
task SampleTask {
methodA param1 param2
}
With << Operator:
Task SampleTask <<{
methodA param1 param2
}
My question is: what is real differences between above 2 ways?
Thanks :)
you can define tasks like this :
task hello {
doLast {
println 'Hello world!'
}
}
here, the last thing that hello task does, is to print 'Hello World!'
I can use another syntax for defining my task like this :
task hello << {
println 'Hello world!'
}
these two tasks are same.
another example is :
task hello << {
println 'Hello Earth'
}
hello.doFirst {
println 'Hello Venus'
}
hello.doLast {
println 'Hello Mars'
}
hello << {
println 'Hello Jupiter'
}
now the output will be :
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter
read documentation for more details.
Related
I have around 25 tests on my android tests package. I have some tests that I to run during integration and some tests that run as normal instrumentation tests. I am trying to call the integration tests using Gradle tasks but it seems impossible for instrumentation tests. I have checked for unit tests and it's possible with something like this-
task integrationTest(
type: Test,
description: 'Run integration tests only. Pass in \'-Pintegration=true\'',
dependsOn: ['testDebugUnitTest', 'clean'] ) {
//Here for task completion, not actually used since sub task of testDebugUnitTest
testClassesDir = file("src/integrationTest/java/");
classpath = files("$System.env.ANDROID_HOME/sources/android-18")
//
//Turn on integration testing when argument exists and is true
//
if (project.hasProperty('integration')) {
println integration
if (integration == 'true') {
integrationTests = true
}
}
}
and doing something like this
testOptions {
unitTests.all {
useJUnit()
if (integrationTests.toBoolean()) {
println "Integration Tests Only for " + it.name
options {
excludeCategories 'com.example.reactivemvp.categories.UnitTest'
}
} else {
println "Unit Tests Only for " + it.name
options {
excludeCategories 'com.example.reactivemvp.categories.IntegrationTest'
}
}
}
}
I have seen that the testOptions only works with unit tests and not with instrumentation tests. I found out what is the method for access the instrumentation tests-
testVariants.all { variant ->
if(connectedInstrumentTest.name)
variant.connectedInstrumentTest.doFirst {
println "This will be executed right after our connectedInstrumentTest!"
println "The name of the test type: $connectedInstrumentTest.name"
if (intergrationTests == true) {
exclude '**/*androidTest.functionalTests*'
}
}
}
I get the error as
Could not find method exclude() for arguments [**/*androidTest.functionalTests*] on task ':app:connectedAndroidTest'
Is there a way to call only a section of the instrumentation tests by some Gradle task?
I'm trying to upload to Crittercism on build, and I put this at the bottom of my gradle file. However, it doesn't seem to be working when I build debug. What am I doing wrong?
task uploadMappingToProd() << {
def critterAppId = "abcde"
def appVersionName = "1.0.1"
def appVersionCode = "DEBUG"
def critterKey = "12345"
commandLine 'curl',
"https://app.crittercism.com/api_beta/proguard/$critterAppId",
'-F', 'proguard=#build/outputs/mapping/production/release/mapping.txt',
'-F', "app_version=$appVersionName-$appVersionCode",
'-F', "key=$critterKey"
type Exec
dependsOn 'assembleDebug'
}
The way you've done it, the task that you have defined, uploadMappingToProd, will if invoked by some reason also invoke assembleDebug. Because you have asked uploadMappingToProd to depend on assembleDebug - not the reverse. Therefore assembleDebug will happily finish without getting anywhere close to uploadMappingToProd.
If you want the reverse dependency i.e. assembleDebug to depend on uploadMappingToProd then you need to add this line after defining your task.
afterEvaluate {
tasks.assembleDebug.dependsOn uploadMappingToProd
}
This will guarantee uploadMappingToProd is invoked everytime and before assembleDebug is invoked.
My solution is working fine.(local build and jenkins build)
for me, only working when build is from jenkins
make sure your APPID, APPKEY, and path(release_jenkins.... normally release)
build.gradle (app) (add at the end)
task uploadPro << {
logger.error("Uploading mapping.txt file to crittercism")
String temp = projectDir;
temp = temp.replace("\\", "/");
String[] cmd = ["curl", "-k", "https://app.crittercism.com/api_beta/proguard/AppIDSting",
"-F", "proguard=#" + temp + "/build/outputs/mapping/release_jenkins/mapping.txt",
"-F", "app_version=" + VERSION_NAME + '-' + VERSION_CODE,
"-F", "key=API_KEY"]
logger.error("CMD : " + cmd)
ProcessBuilder builder = new ProcessBuilder(cmd);
Process process = builder.start();
process.waitFor()
println process.err.text
println process.text
}
gradle.buildFinished {
//check your build type. I am not sure it's the best way to do it.
logger.error("JSC : 이름 ! - " + gradle.startParameter.taskNames);
if (gradle.startParameter.taskNames.contains("assembleRelease_jenkins")) {
logger.error("JSC : 올리기 시작 ! - " + gradle.startParameter.taskNames);
tasks.uploadPro.execute()
} else {
logger.error("JSC : PASS")
}
}
sample project -> https://github.com/SinsangMarket/CrittercismMappingTXT
I am writing a gradle task. The task it invokes returns 3 for successful run instead of 3. How do I go about doing this ?
task copyToBuildShare(){
def robocopySourceDir = "build\\outputs\\apk"
def cmd = "robocopy "+ robocopySourceDir + " C:\\TEST *.* /MIR /R:5 2>&1"
exec {
ignoreExitValue = true
workingDir '.'
commandLine "cmd", "/c", cmd
if (execResult.exitValue == 3) {
println("It probably succeeded")
}
}
}
It gives the error:
Could not find property 'execResult' on task
I don't want to create a separate task. I want it to be in the exec block. What am I doing wrong?
project.exec() has a return value typed ExecResult.
def result = exec {
ignoreExitValue true
executable "cmd"
args = ["/c", "exit", "1"]
}
println "exit value:"+result.getExitValue()
Reference here:
https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:exec(groovy.lang.Closure)
You're going to need to specify that this task is of type Exec. This is done by specifying the task type like so
task testExec(type: Exec) {
}
In your specific case, You'll also want to make sure you don't try to get the execResult until the exec has finished this can be done by wrapping the check in a doLast.
task testExec(type: Exec) {
doLast {
if (execResult.exitValue == 3) {
println("It probably succeeded")
}
}
}
Here's an example of executing ls and checking its return value
task printDirectoryContents(type: Exec) {
workingDir '.'
commandLine "sh", "-c", "ls"
doLast{
if (execResult.exitValue == 0) {
println("It probably succeeded")
}
}
}
I declared this function in my Android project build.gradle:
def remoteGitVertsion() {
def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parse(new URL("https://api.github.com/repos/github/android/commits"))
assert object instanceof List
object[0].sha
}
And this flavor:
android {
...
productFlavors {
internal {
def lastRemoteVersion = remoteGitVersion()
buildConfigField "String", "LAST_REMOTE_VERSION", "\"" + lastRemoteVersion + "\""
}
...
}
...
}
Now, due to gradle declarative nature, the remoteGitVersion function is executed every time the project is built, it doesn't matter if the build flavor is internal or something else. So, the github API call quota is consumed and, after a little while, I receive a nice forbidden message.
How can I avoid this? Is it possible to execute the function only when the selected flavor is the right one?
Took reference from here:
In Android/Gradle how to define a task that only runs when building specific buildType/buildVariant/productFlavor (v0.10+)
To recap:
1. Wrap your flavor specific logic into a task
task fetchGitSha << {
android.productFlavors.internal {
def lastRemoteVersion = remoteGitVersion()
buildConfigField "String", "LAST_REMOTE_VERSION", "\"" + lastRemoteVersion + "\""
}
}
2. Make the task being called whenever you build your variant, and only then.
You could use assembleInternalDebug to hook into, in your case.
tasks.whenTaskAdded { task ->
if(task.name == 'assembleInternalDebug') {
task.dependsOn fetchGitSha
}
}
3. Make sure to remove the dynamic stuff from your flavor definition
productFlavors {
internal {
# no buildConfigField here
}
}
Hope that helps.
I'm new in gradle. How can I run exec one task after another? I've got a problem that task test1 runs before android.applicationVariants.all, and property test is empty,how to change it?
project A
String test = ''
android {
android.applicationVariants.all.doFirst {
test = 'vasya'
}
task test1.doLast{
println "$test"
}
But I've got the following output:
* Where:
Build file '/home/build.gradle' line: 57
* What went wrong:
A problem occurred evaluating project ':ProjectA'.
> No signature of method: java.util.ArrayList.doFirst() is applicable for argument types: (build_6g09fl113rl613 iaq870b0hod0$_run_closure1_closure12_closure18) values: [build_6g09fl113rl613iaq870b0hod0$_run_closure1_closure12_closure18#5f81a4ab]
Possible solutions: first(), toList(), asList(), sort(), sort(groovy.lang.Closure), sort(boolean)
1) Use dependsOn to handle hierarchy:
task helloTask1 << {
println "hello task 1"
}
task helloTask2(dependsOn: helloTask1) {
println "hello task 2"
}
then, calling helloTask2 execustion will trigger helloTask1 first
2) Use mustRunAfter() if needed (this method is in incubating mode):
task helloTask1 {
println "hello task 1"
}
task helloTask2 {
mustRunAfter helloTask1
println "hello task 2"
}
Given two tasks defined:
task mainTask {
println "main"
}
task nextTask {
println "next task"
}
the following code
mainTask << {
nextTask.execute()
}
executes nextTask after mainTask is run:
> gradle mainTask
main
next task
Have a look at task's mustRunAfter method.