Since the Gradle integrated jacoco plugin cannot be used, there is a task skipped problem. I try to use Jacoco Command Line Interface and Exec - Gradle DSL Version 7.0.
def reportTask = tasks.create(reportTaskName, Exec.class) {
group = 'Reporting'
description = "Generate End To End Android Test Jacoco coverage reports on the ${buildVariant.capitalize()} build by Command Line Interface."
workingDir "${project.buildDir}"
commandLine "java", "-jar", "${jacocoCLI}", "report", "${project.buildDir}/outputs/code_coverage/${buildVariant}AndroidTest/connected/*.ec",
"--classfiles", "${project.buildDir}/intermediates/javac/${buildVariant}/classes/",
"--classfiles", "${project.buildDir}/tmp/kotlin-classes/${buildVariant}/",
"--html", "${project.buildDir}/jacocoReport/jacocoHtml/",
"--sourcefiles", "${project.projectDir}/src/main/java",
"--xml", "${project.buildDir}/jacocoReport/jacocoXml.xml"
}
reportTask
When I run this task, I get:
> Task :qtx:jacocoEtoeAndroidTestReportByCLI FAILED
[INFO] Loading execution data file <xxx>/build/outputs/code_coverage/etoeDebugAndroidTest/connected/*.ec.
Exception in thread "main" java.io.FileNotFoundException: <<xxx>>/build/outputs/code_coverage/etoeDebugAndroidTest/connected/*.ec (No such file or directory)
However, if I execute it in the terminal, as shown in the figure below, the task will succeed.
What's the difference between these two usages and how can I use Regular Expressions in Gradle Exec?
UPDATE
def _createAndroidTestCoverageReportByCLI(productFlavorName = "") {
def buildTypeName = "debug"
def buildVariant
buildVariant = "${productFlavorName}${buildTypeName.capitalize()}"
def getExecDataTaskName = "${ANDROID_TEST_REPORT_TASK_PREFIX}${productFlavorName.capitalize()}${ANDROID_TEST_REPORT_TASK_SUFFIX}ExecDataGetter"
def reportTaskName = "${ANDROID_TEST_REPORT_TASK_PREFIX}${productFlavorName.capitalize()}${ANDROID_TEST_REPORT_TASK_SUFFIX}ByCLI"
def jacocoCLI
String execData
project.rootProject.allprojects.each { project ->
if (project.name == "testlib") {
jacocoCLI = "${project.projectDir}/lib/jacococli.jar"
}
}
def getExecDataTask = tasks.create(getExecDataTaskName, JacocoReport.class) {
def listEc = []
def dir = new File("${project.buildDir}/outputs/code_coverage/${buildVariant}AndroidTest/connected/")
dir.eachFileRecurse() { file ->
listEc << file
}
execData = listEc.join(" ")
}
def reportTask = tasks.create(reportTaskName, Exec.class) {
group = 'Reporting'
description = "Generate End To End Android Test Jacoco coverage reports on the ${buildVariant.capitalize()} build by Command Line Interface."
workingDir "${project.buildDir}"
// commandLine "java", "-jar", "${jacocoCLI}", "report", "${execData}",
// "--classfiles", "${project.buildDir}/intermediates/javac/${buildVariant}/classes/",
// "--classfiles", "${project.buildDir}/tmp/kotlin-classes/${buildVariant}/",
// "--html", "${project.buildDir}/jacocoReport/jacocoHtml/",
// "--sourcefiles", "${project.projectDir}/src/main/java",
// "--xml", "${project.buildDir}/jacocoReport/jacocoXml.xml"
commandLine "java -jar ${jacocoCLI} report ${execData} --classfiles ${project.buildDir}/intermediates/javac/${buildVariant}/classes/ --classfiles ${project.buildDir}/tmp/kotlin-classes/${buildVariant}/ --html ${project.buildDir}/jacocoReport/jacocoHtml/ --sourcefiles ${project.projectDir}/src/main/java --xml ${project.buildDir}/jacocoReport/jacocoXml.xml"
}
reportTask.dependsOn getExecDataTask
}
Error
> Task :qtx:jacocoEtoeAndroidTestReportByCLI FAILED
Execution failed for task ':qtx:jacocoEtoeAndroidTestReportByCLI'.
> A problem occurred starting process 'command 'java -jar <RepoPath>/testlib/lib/jacococli.jar report <RepoPath>/QTX/build/outputs/code_coverage/etoeDebugAndroidTest/connected/spoon1619160691046.ec <RepoPath>/QTX/build/outputs/code_coverage/etoeDebugAndroidTest/connected/spoon1619161047292.ec <RepoPath>/QTX/build/outputs/code_coverage/etoeDebugAndroidTest/connected/spoon1619160787358.ec --classfiles <RepoPath>/QTX/build/intermediates/javac/etoeDebug/classes/ --classfiles <RepoPath>/QTX/build/tmp/kotlin-classes/etoeDebug/ --html <RepoPath>/QTX/build/jacocoReport/jacocoHtml/ --sourcefiles <RepoPath>/QTX/src/main/java --xml <RepoPath>/QTX/build/jacocoReport/jacocoXml.xml''
I tried to pass in execfiles through list, the task still failed. When I copied the failed command to the terminal for execution, it could be executed successfully.
Why? How can it be executed in Gradle?
Related
For example, if I wanted a shell script to be able to get the value of rootProject.name, how could I do this? Ideally, I'd like to invoke ./gradlew with some set of arguments and have it print the property value (and nothing else) to stdout.
For clarity, here is my Gradle wrapper version:
$ ./gradlew --version
------------------------------------------------------------
Gradle 5.4.1
------------------------------------------------------------
Build time: 2019-04-26 08:14:42 UTC
Revision: 261d171646b36a6a28d5a19a69676cd098a4c19d
Kotlin: 1.3.21
Groovy: 2.5.4
Ant: Apache Ant(TM) version 1.9.13 compiled on July 10 2018
JVM: 11.0.2 (Oracle Corporation 11.0.2+9-LTS)
OS: Mac OS X 10.14.4 x86_64
This is an existing task to give you an idea of the properties available:
$ ./gradlew properties
> Task :properties
------------------------------------------------------------
Root project
------------------------------------------------------------
allprojects: [root project 'myProject', project ':otherProject', ...]
...
rootDir: /path/to/rootDir
rootProject: root project 'myProject'
...
version: 2.3.0
...
Here is a custom task I've built to print out a project property
class ResolveProperties extends DefaultTask {
#Input
String prop
ResolveProperties() {
// if no --prop=<property> is provided, default to spitting out all properties
prop = "properties"
}
#Option(option = 'prop', description = 'Set the property to be evaluated for the project.')
void setProp(final String prop) {
this.prop = prop
}
#TaskAction
void resolveProp() {
List<String> propPath = this.prop.tokenize('.')
int n = propPath.size()
def currentProp = project
propPath.eachWithIndex { p, i ->
if(currentProp.hasProperty(p)) {
currentProp = currentProp.property(p)
}
else {
throw new GradleException("failed to resolve property: ${this.prop}")
}
}
println "${this.prop} -> ${currentProp}"
}
}
task resolveProperties(type: ResolveProperties)
And this is how I use my custom task with a --prop parameter (indicated by #Option(option = 'prop'. I'm using the -q (quiet) Gradle option to suppress some of the extra output.
$ ./gradlew -q resolveProperties --prop=rootProject.name
rootProject.name -> onestop
resolveProperties took 0 seconds
$ ./gradlew -q resolveProperties --prop=rootProject.version
rootProject.version -> 2.3.0
resolveProperties took 0 seconds
$ ./gradlew -q resolveProperties --prop=rootProject.group
rootProject.group -> org.cedar.onestop
resolveProperties took 0 seconds
Because we are throwing a GradleException when we can't find the property, in Bash you can check the return code of the command to know when to parse out the value. The formatting of a successful output is up to you and you could make it easily parsed.
$ ./gradlew -q resolveProperties --prop=does.not.exist
resolveProperties took 0 seconds
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/elliott/Documents/GitHub/onestop/build.gradle' line: 259
* What went wrong:
Execution failed for task ':resolveProperties'.
> failed to resolve property: does.not.exist
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 0s
In case of a failure like the one above, we get a non-zero return code in Bash, and we know we don't need to try and parse out the value:
$ echo $?
1
Unfortunately, I don't know a simple way in Gradle to only give the value you are concerned with to stdout (prevent some parsing), but this gets you most of the way there with some flexibility.
If it is still relevant ...
Possible Solution A: print value of "rootProject.name" on cmd line
Add task in build.gradle:
/**
* Prints value of property "rootProject.name" to stdout.
*
* Usage: ./gradlew -q printRootProjectName
*/
task printRootProjectName {
doLast {
println(project.findProperty('rootProject').name)
}
}
Possible Solution B: print a property value as provided on cmd line
Add task in build.gradle:
/**
* Print value of property provided in "-Pprop" on command line to stdout.
*
* Usage Example: ./gradlew -q printProperty -Pprop=rootProject.name
*/
task printProperty {
doLast {
// get the "property name" in question from commandline:
String prop = project.findProperty('prop')
if (prop == null) {
return // or use println ...
}
// treat as property name:
Object theProperty = project.findProperty(prop)
if (null == theProperty) {
// try to handle provided information as "nested property"
List < String > thePropPath = prop.split('\\.').toList()
theProperty = project.findProperty(thePropPath.head())
// aux. closure to travel "property path"
def pp = {
s,
t - >
if (s != null && s.hasProperty(t).is(true)) {
return s.property(t)
}
return null
}
thePropPath.tail().each {
item - >
theProperty = pp(theProperty, item)
}
}
println(theProperty ? : "") // or print "null" ...
}
}
I went through the following link and successfully implemented a task which calls build.gradle file from another project. i.e. solution provided by #karl worked for me.
But I need something up on that.
Can somebody help me to know how I can pass command line arguments while calling another build.gradle? Command line argument should be the variable which I have generated from my current build.gradle file.
In my case, I am defining a buildNumber and doing something like this:
def buildNumber = '10.0.0.1'
def projectToBuild = 'projectName'
def projectPath = "Path_till_my_Project_Dir"
task executeSubProj << {
def tempTask = tasks.create(name: "execute_$projectToBuild", type: GradleBuild)
// ****** I need to pass buildNumber as command line argument in "$projectPath/$projectToBuild/build.gradle" ******
tempTask.tasks = ['build']
tempTask.buildFile = "$projectPath/$projectToBuild/build.gradle"
tempTask.execute()
}
You should never call execute directly on any gradle object. The fact it's feasible doesn't mean it should be done and it's highly discouraged since you intrude internal gradle's execution graph structure.
What you need is a task of type GradleBuild which has StartParameter field that can be used to carry build options.
So:
task buildP2(type: GradleBuild) {
buildFile = '../p2/build.gradle'
startParameter.projectProperties = [lol: 'lol']
}
Full demo can be found here, navigate to p1 directory and run gradle buildP2.
You should modify your script in the following way:
def buildNumber = '10.0.0.1'
def projectToBuild = 'projectName'
def projectPath = "Path_till_my_Project_Dir"
task executeSubProj(type: GradleBuild) {
buildFile = "$projectPath/$projectToBuild/build.gradle"
tasks = ['build']
startParameter.projectProperties = [buildNumber: '10.0.0.1']
}
In the project that is executed use project.findProperty('buildNumber') to get the required value.
I have the following simple task in my build:
task generateFile << {
def file = new File("$buildDir/setclasspath.sh")
file.text = "sample"
outputs.file(file)
}
task createDistro(type: Zip, dependsOn: ['copyDependencies','packageEnvironments','jar', 'generateFile']) <<{
from generateClasspathScript {
fileMode = 0755
into 'bin'
}
}
When I run gradle clean build I see the following output:
Cannot call TaskOutputs.file(Object) on task ':generateFile' after task has started execution. Check the configuration of task ':generateFile' as you may have misused '<<' at task declaration
How do I declare the task file creation outputs as an input to the zip task while also ensuring they happen in the execution phase?
If I leave off the << then the clean task wipes the generated file before the ZIP can use it. If I keep them, I get the above error.
It's the opposite as what is being suggested in the comments. You are trying to set the outputs in execution phase. The correct way to do what you are probably trying to do is for example:
task generateFile {
def file = new File("$buildDir/setclasspath.sh")
outputs.file(file)
doLast {
file.text = "sample"
}
}
I'm trying to write a task rule to create a series of tasks that checkout various svn repository locations. Here is my rule:
tasks.addRule("Pattern: svnCheckout<Classifier> - Checks out the indicated svn repo") { String taskName ->
if(taskName.startsWith('svnCheckout')) {
task(name: taskName, type: Exec) {
String classifier = taskName - 'svnCheckout'
String svnDir = svnRepoUrl //defined elsewhere
switch(classifier) {
case 'SourceTrunk':
svnDir += 'branches/CleanBuild/trunk'
break
case 'AutoInstaller':
svnDir += 'Tools/AutoInstaller'
break
case 'ContentAutomation':
svnDir += 'Tools/ContentAutomation'
break
case 'InternalTools':
svnDir += 'Tools/Internal'
break
default:
throw new GradleException("Invalid svnCheckout classifier '$classifier'")
}
String svnCommand = "svn co $svnDir --trust-server-cert"
//commandLine 'cmd', '/c', "$svnCommand"
commandLine 'cmd', '/c/', "echo 'Task created'"
workingDir = "$workspace"
}
}
}
I then try to run the task 'svnCheckoutSourceTrunk' with this command:
gradlew -Pworkspace="." svnCheckoutSourceTrunk
which fails with the error
FAILURE: Could not determine which tasks to execute.
* What went wrong:
Task 'svnCheckoutSourceTrunk' not found in root project 'GradleScripts'.
* Try:
Run gradlew tasks to get a list of available tasks.
BUILD FAILED
Anyone see what I'm doing wrong? I put some println statements around the first few lines, and the execution is getting past the if statement, but it's not getting inside the task declaration.
The syntax used for declaring the task(s) is incorrect. (Not sure why it's not giving an error.) The first positional argument always need to be the task name:
task(taskName, type: Exec) { ... }
In a build script, this will also work:
task "$taskName"(type: Exec) { ... }
I've recently been directed to implement all build/release engineering jobs in Gradle.
So I'm new to Gradle and some things which are drop-dead obvious at a shell prompt are just hard to fathom in this brave new world.
My build creates a set of jar files.
I need to execute a shell task for each one of them
Something similar to:
task findBugs (type:Exec, dependsOn: fb23) {commandLine 'java', '-jar',
'./findBugs/findbugs.jar', '-textui', '-progress', '-xml', '-output',
'TrustManagerService.xml', 'TrustManagerService.jar'}
(I can't usethe FindBugs plug-in because we're in JDK8 - so I'm running FindBugs externally from a preview version...)
I can get a file collection and iterate over the file names with something like:
FileTree iotTree = fileTree(dir: '.')
iotTree.include '*.jar'
iotTree.each {
File file -> println file.name
println 'A file'
}
or
def iotJars = files(file('./jars').listFiles())
println ''
println iotJars
iotJars.each { File file -> println 'The next file is: ' + file.name }
But for the life of me I can't see how to execute a shell command for each filename returned...
Thoughts on the most straightforward way to do this??
By the way - what's the best way to include the line breaks in the code listing - I had to return and add CRs to each line to get them to break...:(
You can use the execute method on a String to execute a shell command.
Here is an example task:
task executeExample << {
FileTree ioTree = fileTree(dir: ".")
ioTree.each { f ->
def proc = "ls -l ${f}".execute();
proc.waitFor();
println "return code: ${ proc.exitValue()}"
println "stderr: ${proc.err.text}"
println "stdout: ${proc.in.text}"
}
}