I'm using Gradle. I have two tasks: "a" and "b". I want task "a" to call task "b". How can I do this?
task b(type: Exec) {
description "Task B"
commandLine 'echo', 'task-b'
}
task a(type: Exec) {
description "Task A"
commandLine 'echo', 'task-a'
// TODO: run task b
}
In Ant this is a piece of cake:
<target name="a">
<echo message="task-a"/>
<antcall target="b"/>
</target>
<target name="b">
<echo message="task-b"/>
</target>
The first method I tried is using the "dependsOn" feature. However this is not ideal as we would need to think of all the tasks in reverse and also has several other issues (like running a task when a condition is satisfied).
Another method I tried is:
b.mustRunAfter(a)
However this only works if I run the gradle tasks like so:
gradle -q a b
Which is also not ideal.
Is there anyway to simply just call another task from an existing task?
As suggested one method would be to add a finalizer for the task
task beta << {
println 'Hello from beta'
}
task alpha << {
println "Hello from alpha"
}
// some condition
if (project.hasProperty("doBeta")) {
alpha.finalizedBy beta
}
Then we can execute the other task if needed. As for executing tasks from another tasks you cannot do that. Task declaration is declarative not imperative. So a task can depend on another task but they cannot execute another task.
$ gradle -q alpha
Hello from alpha
$ gradle -q alpha -PdoBeta
Hello from alpha
Hello from beta
You can use
a.dependsOn 'b'
Or
a.dependsOn b
Or
task a(type: Exec, dependsOn: 'b') { ... }
etc
See adding dependencies to tasks
To summarize and combine the answers from #JBirdVegas and #lance-java, using non-deprecated doLast instead of leftShift (<<):
task beta {
doLast {
println 'Hello from beta'
}
}
task alpha {
doLast {
println 'Hello from alpha'
}
}
// some condition
if (project.hasProperty('doBeta')) {
alpha.finalizedBy beta // run 'beta' after 'alpha'
// or
// alpha.dependsOn beta // run 'beta' before 'alpha'
}
It is working fine but providing a warning as Deprecated Gradle features were used in this build, making it incompatible with Gradle 5.0.
I am using gradle version 4.7. So it means some of the features you have added in the build.gradle will not work as it is in gradle 5.0.
Run the Gradle build with a command line argument --warning-mode=all to see what exactly the deprecated features are.
It will give you a detailed description of found issues with links to the Gradle docs for instructions how to fix your build.
Related
I have a task in build.gradle, looking like this:
task sourceJar(type: Jar, dependsOn: classes) << {
classifier = 'sources'
from sourceSets.main.allSource
}
Running gradle sourceJar creates a jar file in libs/ but it is empty (does not include any sources, just the manifest).
Removing << fixes it for some reason, the jar is created properly, but screws up other things (the subprojects now lose the compile dependencies, that are defined for them specifically).
So, three (maybe, four?) questions here:
(1) what's wrong? Why sourceSets are empty when the task is defined with <<?
(2) why does removing << fix it? My understanding is that it just makes the insides of the block to be executed "inline", every time, not just when the task is specifically exacuted.
(3) How to fix this? I can't just remove <<, because, like I said, it screws up other things (but see question #4).
(4) Why does removing << screws up subprojects? Is this expected?
To clarify, here is what I am talking about:
subprojects {
apply plugin: 'java'
dependencies {
compile project(':a')
}
task cp << {
println ("PROJECT " + project.name + ">> " + sourceSets.main.runtimeClasspath.collect { it.absolutePath }.join(':'))
}
}
project(':b') {
dependencies {
compile project(':c')
}
}
Running gradle -q b:cp prints out
PROJECT b>> b/build/classes/main:b/build/resources/main:a/build/libs/a.jar:c/build/libs/c.jar
(I removed the absolute paths). This is what I want.
Now, if I remove << from the file, and run gradle -q b:cp again, I get this
PROJECT a>> a/build/classes/main:a/build/resources/main:/a/build/libs/a.jar
PROJECT b>> b/build/classes/main:b/build/resources/main:a/build/libs/a.jar
PROJECT c>> c/build/classes/main:c/build/resources/main:a/build/libs/a.jar
This is wrong in two ways: first, I did not ask it to be run for all three subprojects, just for b, and second, notice that b does not have c in its classpath any more.
Can someone with a clue please help me figure out what's going on here ... I am really about to give up and switch to sbt (yes, it is a threat!).
When you declare a task of type:Jar, you do not have to use <<, because you're effectively extending a jar task which already has all the required << declared correctly. But first it sounds like you need to read up on what << means and about gradle's configuration and execution phases.
Please see Peter's answer here: Why is my Gradle task always running?
(<< is gradle shorthand for doLast any task code that isn't enclosed in doLast or isn't annotated by << is executed in the configuration phase and not execution phase. This can cause your printlns for example to be executed when the task isn't explicitly invoked, because all tasks are configured even if they are not executed)
Second, your cp task isn't extending a task type. so this needs << in its definition.
task cp << { ... }
I have been trying to execute a jar file ssr.runner, jar using task with type JavaExec. But gradle is giving me the error that no main class specified. I am new to gradle so if any one could please elaborate in detail that would be great. Here is the task that I wrote:
task executeSqlScriptRunnerBeforeTenantCreation(type:JavaExec) {
description "Execute ssr.runner to install certificates into the device"
doLast {
if(scriptRunnerVariables.get('SSR_INTERSECT_MOCK') == 'true') {
println "Executing SQL Script Runner..."
println "Adding certificates for mocked intersect service"
if(scriptRunnerVariables.get('SSR_DB_TYPE') == 'SQL_SERVER') {
classpath = file("{$workingDir}\\ssr.runner.jar")
main = '-jar'
args '-dbtype', "${scriptRunnerVariables.get('SSR_DB_TYPE')}", '-dbhost', "${scriptRunnerVariables.get('SSR_DB_HOST')}", '-dbinstance',
"${scriptRunnerVariables.get('SSR_DB_INSTANCE')}", '-dbname', "${scriptRunnerVariables.get('SSR_DB_NAME')}", '-dbuser', "${scriptRunnerVariables.get('SSR_DB_USER')}",
'-dbpass', "${scriptRunnerVariables.get('SSR_DB_PASS')}", '-sqlscriptpath', "${scriptRunnerVariables.get('SSR_INTERSECT_MOCK_DB_SCRIPT')}"
}
}
}
}
First of all you're mixing two phases: execution and configuration. There's no need to add doLast for predefined tasks. See here. Then this is (probably) how the script should look like:
task executeSqlScriptRunnerBeforeTenantCreation(type:JavaExec) {
description "Execute ssr.runner to install certificates into the device"
if(scriptRunnerVariables.get('SSR_INTERSECT_MOCK') == 'true') {
println "Configuring SQL Script Runner..."
println "Adding certificates for mocked intersect service"
if(scriptRunnerVariables.get('SSR_DB_TYPE') == 'SQL_SERVER') {
main = '<FULLY QUALIFIED NAME OF CLASS YOU NEED TO RUN>'
classpath = file("{$workingDir}\\ssr.runner.jar")
args '-dbtype',
"${scriptRunnerVariables.get('SSR_DB_TYPE')}",
'-dbhost',
"${scriptRunnerVariables.get('SSR_DB_HOST')}",
'-dbinstance',
"${scriptRunnerVariables.get('SSR_DB_INSTANCE')}",
'-dbname',
"${scriptRunnerVariables.get('SSR_DB_NAME')}",
'-dbuser',
"${scriptRunnerVariables.get('SSR_DB_USER')}",
'-dbpass',
"${scriptRunnerVariables.get('SSR_DB_PASS')}",
'-sqlscriptpath',
"${scriptRunnerVariables.get('SSR_INTERSECT_MOCK_DB_SCRIPT')}"
}
}
}
}
main was misconfigured there should be a fully qualified (with package) name of java class you need to run passed. Of course, what is configured via classpath, main, args and so on in configuration phase will be run in execution phase only if the two expressions in if block evaluate to true.
We are developing a Java project that is able to instrument (change) class files at build time. We defined a Gradle task that invokes a java based Ant task which takes an inputDir (e.g. build/classes) and an outputDir (e.g. build/classes-instrumented) and possible other parameters. The task gets invoked separately for main and test class files after compilation. Since the "normal" java sourceSet is not a good fit, our first thought was to implement our own sourceSet but couldn't find an easy way. A reasonable alternative, similar to ANTLR etc, seemed to be extra variables. Since I needed several, I went for a Map.
sourceSets.all { ext.instrumentation = [:] }
sourceSets.all {
instrumentation.inputDir = null
instrumentation.outputDir = null
instrumentation.classPath = null
}
def postfix = '-instrumented'
Below you see how we initialize the variables.
sourceSets {
main {
instrumentation.inputDir = sourceSets.main.output.classesDir
instrumentation.outputDir = instrumentation.inputDir + postfix
instrumentation.classPath = sourceSets.main.output + configurations.compile
}
test {
instrumentation.inputDir = sourceSets.test.output.classesDir
instrumentation.outputDir = instrumentation.inputDir + postfix
}
}
However it fails with "Could not find method main() for arguments [build_f2cvmoa3v4hnjefifhpuk6ira$_run_closure5_closure23#12a14b74] on root
project 'Continuations'."
We are using Gradle 2.1
I have the following questions:
any idea why the first one fails?
Is the extra variable a reasonable solution to approach the problem?
Thanks a lot for your help
solution: install last version.
I had the same problem, I read gradle documentation of gradle 3, but gradle 2.7 was installed.
checked gradle version 2.7
then read gradle 2.7 doc https://docs.gradle.org/2.7/userguide/tutorial_java_projects.html#N103CD , but found no info about sourceSet in java plugin for that version
installed gradle 3 --> problem solved
One of my build tasks pulls information on the current SVN branch. On builds from a tag I want to be more strict and fail the build when e.g., a link checker finds dead links for the online help files. On regular builds from branches or trunk this should not break the build.
I have the following code, where the mentioned Perl script creates a properties file:
task generateSvnInfo(type: Exec) {
outputs.files "generated/svninfo"
executable "perl"
args "..."
}
Properties buildProps = new Properties()
task svninfo() {
inputs.files generateSvnInfo.outputs.files
outputs.upToDateWhen { false }
buildProps.load(new FileInputStream(inputs.files.getSingleFile()))
}
Now my other targets depend on svninfo (and the fact that it populates buildProps).
task checkHelpLinks(type: Exec) {
dependsOn "svninfo"
executable "perl"
args "..."
}
This will always fail if it finds dead help links. As far as I understand it, ignoreExitValue is false by default. To set it to true on non-tag builds, I can add this to the checkHelpLinks task:
ignoreExitValue = true
doLast {
ignoreExitValue = buildProps.FROM_TAG == "false"
}
This works, but I have four or five of these check tasks and would like to not duplicate that code around. So I tried
tasks.grep(~ /^check.+/).each { task ->
task.ignoreExitValue = true
task.doLast {
task.ignoreExitValue = buildProps.FROM_TAG == "false"
}
}
This code does not seem to get executed. I thought that may be because I compare the Task object to a String in grep, but using
tasks.grep(it.name =~ /^check.+/).each { task ->
gets me a build script error ("Could not find property 'it' on root project 'foo'.)
How can I add my tag check to all check tasks?
Is there a better way to load the properties from a file that is created as part of the build process?
Is there a SVN plugin that would do the work for me?
Basically I have 4 tasks that I need to run sequentially, but I cannot make them do so, I have to run it one by one on the command line as so:
gradle :drmdexsecondary:compileReleaseJava --info --debug --stacktrace
gradle :drmdexsecondary:dexClasses --info --debug --stacktrace
gradle :drmdexsecondary:jar --info --debug --stacktrace
Here's my build.gradle:
evaluationDependsOnChildren();
task dexClasses( type:Exec ) {
// compileJava.execute()
String cmdExt = Os.isFamily(Os.FAMILY_WINDOWS) ? '.bat' : ''
println("${buildDir}")
println("${androidSdkDir}\\build-tools\\${buildToolsVersion}\\dx${cmdExt} --dex --output=${buildDir}\\classes\\classes.dex ${buildDir}\\classes\\release")
commandLine "cmd", "/c", "${androidSdkDir}\\build-tools\\${buildToolsVersion}\\dx${cmdExt} --dex --output=${buildDir}\\classes\\classes.dex ${buildDir}\\classes\\release"
}
task jar(type: Jar) {
from ("${buildDir}\\classes\\classes.dex")
}
My problem is this:
the dependsOn keyword doesn't work... it just get ignored without any log message
taskname.execute() function doesn't work... it just get ignored without any log message
compileReleaseJava is not recognized inside build.gradle with this particular error: Could not find property 'compileJava' on task ':drmdexsecondary:dexClasses'.
Would anyone please help?
I've consulted and copy paste from the documentation but none of them seems work. I've even tried to re-install Gradle... there is so few sample codes there and although I understand the concept, it seems so difficult to translate my intention into working Gradle code, so if there is any good resources to help, it will be very appreciated as well.
You should read about gradle tasks and more about tasks. You want to depend on things rather then invoke things.
Also I think you should read about, and use the gradle android plugin.
To your original question, when you define a task the code between the braces is run at configuration time. A task's actions are run when the task is executed and must be added to the task's action list. This is done by using the task's doFirst, doLast or the << operator.
Here is an example from the gradle documentation.
task taskX << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
task taskZ << {
println 'taskZ'
}
taskX.dependsOn taskY
taskY.dependsOn taskZ
taskZ.shouldRunAfter taskX
task1.finalizedBy task2 will run task2 after task1.
The Best Answer is Here
task myTask1() {
println("this is task1 running")
}
task task2() { dependsOn myTask1
println("this is task2 running")
}
when you execute gradle task2 .
this wil first execute task1 ,and then execute task2
you should use dependsOn key words
For example
task buildMyApk(type: Exec) {
def myCommond = ['gradle', "assembleRelease"]
commandLine myCommond
}
task moveApkFileToProjectFolder() { dependsOn buildMyApk
def releaseApkFilePath = "${buildDir}/outputs/apk/release/"
def targetApkFolder = "${rootProject.getProjectDir()}/apkFolder"
mkdir "${targetApkFolder}"
copy{
from releaseApkFilePath
into targetApkFolder
}
}
above answer will not work
task moveApkFileToProjectFolder run ,will first run buildMyApk.
my example task ,first will build apks .and then move apk File to my Project/apkFile folder .and execute success.
You can create a task of type GradleBuild and define the tasks inside of that task.
task releaseAfterMath(type: GradleBuild) {
tasks = [
'clean',
'build',
'publish',
'publishToMavenLocal',
'commitNewVersionTask',
'gitChangelogTask',
'commitChangelogTask'
]
}
And you can trigger releaseAfterMath like any other task. Running code here:
https://github.com/tomasbjerre/gradle-scripts/
For sequential or whatever the sequence you want to run your tasks, I do the following thing in my build.gradle file:
def modules = ["X", "Y", "Z", "ZZ"]
if (modules.size() > 1) {
for(j in 1 .. modules.size()-1 ) {
tasks[modules[j]].mustRunAfter modules[values[j-1]]
}
}