Gradle task should not execute automatically - gradle

I'm defining a task in gradle:
task releaseCandidate(type: Exec) {
commandLine 'git', 'checkout', 'develop'
// Increment version code in Manifest
String manifest = new File('AndroidManifest.xml').getText('UTF-8')
Pattern pattern = Pattern.compile('android:versionCode="([0-9]+)"')
Matcher matcher = pattern.matcher(manifest)
matcher.find()
int newVersionCode = Integer.parseInt(matcher.group(1)) + 1
manifest = manifest.replaceAll(
"android:versionCode=\"([0-9]+)\"", "android:versionCode=\"$newVersionCode\""
)
new File('AndroidManifest.xml').write(manifest, 'UTF-8')
commandLine 'git', 'diff'
}
Which I want to execute only when I explicitly call it as gradle releaseCandidate. However, when I run any other task, such as gradle assembleDebug, it also runs task releaseCandidate. I don't want that behaviour to happen. There is no task depending on releaseCandidate or vice-versa.
My project is an Android app, so I am using android gradle plugin.

A common pitfall. Add an action to the task otherwise code will run at configuration phase. Sample task with action:
task sample << {
}
As I see You'd rather need to write a custom task than using Exec type. I suppose it's not valid to define commandLine twice.
EDIT
You can read this post to get the general idea how it all works.

You are mixing Task configuration and groovy code. Everything that is part of the main body of a task definition will be executed in the configuration phase. The task task1 << { code } is a shorthand for
task task1 {
doLast {
code
}
}
commandLine is part of the Exec Task but your other code is not and should be wrapped into a doLast this will execute the commandline first and then execute your additional code. If you need another exec commandLine then you'll need another task.
task releaseCandidate(type: Exec) {
commandLine 'git', 'checkout', 'develop'
doLast {
// Increment version code in Manifest
String manifest = new File('AndroidManifest.xml').getText('UTF-8')
Pattern pattern = Pattern.compile('android:versionCode="([0-9]+)"')
Matcher matcher = pattern.matcher(manifest)
matcher.find()
int newVersionCode = Integer.parseInt(matcher.group(1)) + 1
manifest = manifest.replaceAll(
"android:versionCode=\"([0-9]+)\"", "android:versionCode=\"$newVersionCode\""
)
new File('AndroidManifest.xml').write(manifest, 'UTF-8')
}
}

Just to complete #Opal answer for cases when Exec is really used (for example CommandLine reference) :
task task1 << {
exec {
List<String> arguments = new ArrayList<String>()
//..
commandLine arguments
}
}

Related

How to pass text parameters into a Gradle task from another gradle task (not command line)

I'm wondering how I can pass a parameter (PARAM) to a Gradle task from another Gradle task that depends on it.
For example something along these lines
task buildDist(PARAM) {
copy {
from "$projectDir/src/{PARAM}/ClientBanner.json"
into "$buildDir/${project.name}/"
}
and call this Gradle task from another one like:
task dist(type: Zip) {
from "$buildDir"
include "${project.name}/**/*"
archiveFileName = project.name + '.zip'
destinationDirectory = layout.buildDir.dir('dist')
dependsOn('buildDist(PARAM)')
}
#Shapebuster
The Gradle build script is Groovy (or Kotlin) based and can be extended using the supported syntax of that language. So, in your example, you should be able to use the PARAM like so:
task buildDist(String param1) {
copy {
from "$projectDir/src/$param1/ClientBanner.json"
into "$buildDir/${project.name}/"
}
}
and then:
task dist(type: Zip) {
from "$buildDir"
include "${project.name}/**/*"
archiveFileName = project.name + '.zip'
destinationDirectory = layout.buildDir.dir('dist')
dependsOn buildDist("$param1")
}

Error using dependsOn to call task from another gradle file

I am working with a build.gradle file that has multiple ways to specify executions for a task - setup. To call a task from another gradle file - runtests.gradle, I created a task - testTask and added task dependency using dependsOn, but this implementation does not seem to work and giving out an error like :
Could not find property 'testTask' on root project 'GradleFile
My build file looks like this :
build.gradle
task setup(dependsOn: testTask) <<
{
println "In main execution"
}
// new task
task testTask(type: GradleBuild) {
if (getEnvironmentVariable('RUN_TEST').equalsIgnoreCase("true")) {
buildFile = "../Behave/runtests.gradle"
tasks = ['mainTask']
}
else {
println "Exiting runTests Task"
}
}
setup.doFirst {
println "In first execution"
}
setup.doLast {
println "In last execution"
}
D:\>gradle -q GradleFile/build.gradle setup
I am not looking to make much changes to existing tasks, so is there any other workaround I should try?
I have been through many links but could not find anything that suits this scenario. Looking for suggestions please.
Gradle is sensitive to the ordering of tasks in the build script if a task instance is given in the dependsOn. The task setup depends on task (instance) testTask which, at the moment the build script is compiled, doesn't exist yet. The most common options to solve the issue are:
Define task setup below testTask:
task testTask(type: GradleBuild) {
}
task setup(dependsOn: testTask) {
}
Use a relative path to the task, i.e. the task's name, in the dependsOn
task setup(dependsOn: 'testTask') {
}
task testTask(type: GradleBuild) {
}
Please find more details in Javadoc of Task.

Gradle task lines always getting executed

I have the following Gradle task:
task deploy(type: Exec) {
doFirst {
println 'Performing deployment'
}
final Map properties = project.getProperties()
if (!properties['tag']) {
throw new StopExecutionException("Need to pass a tag parameter")
}
commandLine "command", tag
}
If I run another task I get an error because properties['tag'] is undefined, I guess because Gradle is executing everything in the task except commandLine. Is there a better way to do this or a way to stop Gradle from executing parts of the task even when I'm running another task?
Using Gradle 6.6.1
I use this pattern:
// Groovy DSL
tasks.register("exec1", Exec) {
def tag = project.findProperty("tag") ?: ""
commandLine "echo", tag
doFirst {
if (!tag) {
throw new GradleException("Need to pass a tag parameter")
}
}
}
It adds the tag property if it exists.
If it does not exist, it adds an empty string but checks for this before it actually runs.
It would be great if the Exec task accepted providers as arguments so you could just give it providers.gradleProperty("tag"), but unfortunately it doesn't.

Gradle, task type: Exec - commandLine not work in onLast

I want execute some command from command line in gradle task(e.g. print all files in dir):
task dir(type: Exec) {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
doLast {
println ("result = " + standardOutput)
}
}
It's work. OK. But when I put it on onLast section it's not work:
task dir(type: Exec) {
doLast {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
println ("result = " + standardOutput)
}
}
I get error:
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':app:dir'.
execCommand == null!
The reason is in the fact, that task of Exec should be configured during configuration phase of the build, otherwise your task will be not configured and fail.
In you first example everything works due to configuration happens at the configuratyion phase. Your second example tries to configure the task within doLast closure - right after the task is executed yet.
If you really need to execute something in doLast, you can use something like this, without creating special task:
task someTaskName {
doLast {
exec {
commandLine adbCommand
}
}
}
Here is exec-specification used to execute some command and it's configured and executed at the same time.

Gradle aggregation task

In my gradle scripts, I've built a task that runs a java process. This process depends on a target property. The task is defined by:
task('bulk', type: JavaExec, dependsOn: 'classes', description : 'Bulk data import on a target (defined by -Ptarget=[event|member|...]]') {
//available imports
ext{
event = relativePath('src/main/scripts/events.csv')
member = relativePath('src/main/scripts/member.csv')
membership = relativePath('src/main/scripts/membership.csv')
}
//check the target is set
doFirst {
if(!project.hasProperty('target')){
println "\nUsage:"
println "\tgradle bulk -Ptarget=[event|member|...]"
println "where target is : "
bulk.ext.each{ println it }
throw new GradleException('Target argument required')
} else {
println "\nBulk import of $target\n"
}
}
main = 'org.yajug.users.bulkimport.BulkImport'
classpath = sourceSets.main.runtimeClasspath
if(project.hasProperty('target')){
bulk{
args target
args bulk.ext[target]
debug false
}
}
}
And to run it:
gradle bulk -Ptarget=event
It's working fine, but know I have to run this process for different targets:
gradle bulk -Ptarget=event
gradle bulk -Ptarget=member
gradle bulk -Ptarget=membership
...
How can I group all these calls into an other single task with the gradle's dependency model ? (I know the list of targets)
SOLUTION
task bulk;
['event','member','membership'].each {target ->
task("bulk${target}", type: JavaExec, dependsOn: 'classes', description : "Bulk data import of ${target}s") {
//available imports
ext{
event = relativePath('src/main/scripts/events.csv')
member = relativePath('src/main/scripts/member.csv')
membership = relativePath('src/main/scripts/membership.csv')
}
//check the target is set
doFirst {
println "\nBulk import of $target\n"
}
main = 'org.yajug.users.bulkimport.BulkImport'
classpath = sourceSets.main.runtimeClasspath
args target
args ext[target]
debug false
}
bulk.dependsOn("bulk${target}")
}
How can I group all these calls into an other single task with the gradle's dependency model ?
You can't, because a task (instance) will be executed at most once per build. Instead, the way to go is to declare multiple task instances. You could do this by putting the task declaration in a loop, putting it in a method and calling it multiple times, or by writing a task class and instantiating it multiple times. Then you'll add one other task that depends on all bulk tasks. Assuming the execution order between bulk tasks is irrelevant, that's it.
By adding a helper method or two, you can create a nice little API around this, to improve readability and allow reuse in other places.
Another way to tackle this is with a task rule. You can read more on task rules in the Gradle User Guide.
What about creating a -Ptarget=all, and deal with that specific case in the build.gradle file. This could be done as:
['event','member','membership'].each { t ->
task("bulk${t}", ...) {
onlyIf project.hasProperty("target") && (project.getProperty("target").equals(t) || project.getProperty("target").equals("all"))
args target
args bulk.ext[target]
debug false
}
}

Resources