MyTask getting unwantedly executed when building - gradle

I want to print a link to our team's documentation if the developer types:
gradle help
using this task:
task help {
println "Full Documentation"
println "https://confluence.org.com/Help"
}
which it does.
However, I do not want it to execute when I run:
gradle build
Is the help task supposed to run whenever build is run? If not, why does this task get executed? As you can tell, my understanding of gradle is limited.

You are effectively overriding the built-in help task that Gradle provides. As a result, other tasks or plugins in your project may be referencing that task already or other parts in the overall Gradle build rely or use help in some fashion.
To summarize, do not override Gradle built-in tasks otherwise it will lead to unexpected/unintended consequences.
To fix, rename your task to something other than help.

Related

Passing property to Gradle Tooling API ProjectConnection

I am using gradle tooling api and I encountered the following scenario.
There is a project that applies a certain plugin P which creates a task T only if the property shouldApplyP is passed.
Hence, if you will run ./gradlew tasks --all you won't see task T, but if you will run
./gradlew -PshouldApplyP tasks --all you will see task T.
In gradle tooling api, once a ProjectConnection has created I can do
connection.getModel(GradleProject.class).getTasks()
But I can't see this specific task. Is there a way to pass the project connection this property
-PshouldApplyP so it will be presented in the getTasks() method?
connection.newBuild()
.withArguments("-PshouldApplyP", "tasks --all")
.run()

How can I configure Gradle google-java-format plugin to run goJF in the build step?

We wired https://github.com/sherter/google-java-format-gradle-plugin into our project per the readme.
We also wired in a pre-commit hook to run the plugin before committing, which ensures that all of the code in a changelist is formatted before pushing it, which avoids errors in Jenkins when we run the verGJF task.
But we have to keep remembering to run goJF locally before running ./gradlew build, or the build fails with formatting errors.
We worked around this by adding the https://plugins.jetbrains.com/plugin/8527-google-java-format and https://plugins.jetbrains.com/plugin/7642-save-actions plugins for IntelliJ, enabling the google-java-format plugin, and configuring the save-actions plugin to format on save.
But that's a lot of extra configuration a developer has to remember to go through, plus it means they can't format code the way they want while working on it, and only have it be reformatted at the point of build or commit.
We'd prefer an all-Gradle solution, so that the goJF task is run before the build task (and before the verGJF task, which is already bound to the build task by the google-java-format Gradle plugin).
We couldn't figure out how to do that. Does someone else know?
It sounds like you want to essentially always ensure that the code is properly formatted before the verifyGoogleJavaFormat task is run (and could complain). In that case, I’d simply make the googleJavaFormat task a dependency of the verifyGoogleJavaFormat task. In your build.gradle file, after you have applied the google-java-format plugin, simply add the following:
verifyGoogleJavaFormat.dependsOn(tasks.googleJavaFormat)
Alternatively, if you really only want to run the code formatter when the build task is run (as opposed to when the verifyGoogleJavaFormat task is run only), you could add this instead:
build.dependsOn(tasks.googleJavaFormat)
verifyGoogleJavaFormat.mustRunAfter(tasks.googleJavaFormat)

Gradle shouldRunAfter not available for a task

I created this repo to reproduce exactly what I'm seeing. I have a project that I'm building with Gradle. I would like to configure my Gradle build so that running:
./gradlew build
Has the exact same effect as running:
./gradlew clean build scalafmt shadowJar fizzbuzz
Meaning Gradle calls tasks in the following order:
clean
build (compile & run unit tests)
scalafmt (run a tool that formats my code to a styleguide)
shadowJar (creates a self-contained executable "fat" jar)
fizzbuzz (prints out "Fizzbuzz!" to the console)
According to the Gradle docs on ordering tasks, it seems that I can use shouldRunAfter to specify ordering on all tasks...
If you clone my repo above and then run ./gradlew build you'll get the following output:
./gradlew build
Fizzbuzz!
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/myUser/thelab/idea-scala-hate-each-other/build.gradle' line: 65
* What went wrong:
A problem occurred evaluating root project 'idea-scala-hate-each-other'.
> Could not find method shouldRunAfter() for arguments [task ':build'] on cz.alenkacz.gradle.scalafmt.PluginExtension_Decorated#6b24ddd7.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 10.983 secs
So even though I specify fizzbuzz to run last...its running first! And there are (obviously) errors with the rest of my config. And I'm not sure how to "hook" clean so that even when I run ./gradlew build it first runs clean.
I'd be OK with a solution that requires me to write my own "wrapper task" to achieve the order I want, and then invoke it, say, via ./gradlew buildMyApp, etc. Just not sure how to accomplish what I want.
Update
I made some changes to build.gradle and am now seeing this:
./gradlew fullBuild
:compileJava UP-TO-DATE
:compileScala
:processResources UP-TO-DATE
:classes
:jar
:startScripts
:distTar
:distZip
:assemble
:compileTestJava UP-TO-DATE
:compileTestScala UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
:clean
:fizzbuzz
Fizzbuzz!
:scalafmt
:shadowJar
:fullBuild
So when I run ./gradlew fullBuild task execution seems to be:
build (which calls compileJava through check)
clean
fizzbuzz
scalafmt
shadowJar
So the ordering is still wrong even given my most recent changes...
As Oliver already stated, you need to put the console output to a doFirst or doLast closure, otherwise it will be executed when the task is defined (during configuration phase).
The exception is caused by the fact that both extension properties and tasks are added to the scope of the Project object, but if both an extension property and a task with the same name (scalafmt in this case) exist, the extension property will be accessed. As the error message tells you, you are trying to access the shouldRunAfter method on an object of the type PluginExtension, where it does not exist. You need to make sure to access the task:
tasks['scalafmt'].shouldRunAfter build
Update
Actually, I thought that you only need the two specific problems to be solved, but already have a solution for your basic Gradle structure.
First of all, both shouldRunAfter and mustRunAfter do not actually cause a task to be executed, they only define the order if both tasks are executed (caused by command line or a task dependency). This is the reason why the tasks clean, scalafmt, shadowJar and even fizzbuzz are not executed if you call gradle build. So, to solve your first problem, you could let the build task, which you call explicitly, depend on them:
build.dependsOn 'clean', 'scalafmt', 'shadowJar', 'fizzbuzz'
But a task dependency will always run before the parent task, so all tasks will be executed before the build task. This should not be a problem, since the build task does nothing more than collecting task dependencies for all required build steps. You would also need to define the order not only between of your task dependencies, e.g. clean and the parent task build, but mainly between the existing task dependencies, e.g. compileJava. Otherwise clean could run after compileJava, which would delete the compiled files.
Another option would be to define a new task, which then depends on all the tasks you want to execute:
task fullBuild {
dependsOn 'clean', 'build', 'scalafmt', 'shadowJar', 'fizzbuzz'
}
This would still require to define the order between your tasks and the existing task dependencies, e.g.
compileJava.mustRunAfter 'clean'
[...]
Please note, that now you would have to call gradle fullBuild from command line. If you really need to only call gradle build via command line and still execute some tasks after the actual build task, you could use a little trick in your settings.gradle file:
startParameter.with {
if (taskNames == ['build']) {
taskNames = ['clean', 'build', 'scalafmt', 'shadowJar', 'fizzbuzz']
}
}
This piece of code checks the task name input you entered via command line and replaces it, if it only contains the build task. This way you would not have to struggle with the task order, since the command line tasks are executed consecutively.
However, this is not a clean solution. A good solution would include the definition of task dependencies for all tasks that really depend on each other and the invocation of multiple tasks via command line (which you want to avoid). Especially the hard connection between the clean and the build task bypasses a lot of useful features from the Gradle platform, e.g. incremental builds.
Regarding your second point in the update, it is wrong that the fizzbuzz task is running first. It is not running at all. The command line output is printed when the task is configured. Please move the println call to a doFirst / doLast closure:
task fizzbuzz {
doFirst {
println "Fizzbuzz!"
}
}
One of the possible causes of that error could be because Gradle couldn't compile the task of the method shouldRunAfter or mustRunAfter.
Also it could happen when there is another entity of other type (not a task) with the same name of the task of the method shouldRunAfter or mustRunAfter. In this case you could use the syntax tasks['task1_name'].shouldRunAfter tasks['task2_name'] or tasks['task1_name'].mustRunAfter tasks['task2_name'] to make sure Gradle is referencing a task type entity.

How to control the order of child project Gradle tasks from root build?

I have a Gradle project with two subprojects:
backend
frontend
I want to create a task in the parent project called stage which executes :backend:build but only after running :frontend:clean and :backend:clean.
I tried this but the mustRunAfter is ignored and the cleaning happens at the end of the build instead. What is wrong with it?
task stage(dependsOn: [':frontend:clean', ':backend:clean', ':backend:build'])
task(":backend:build").mustRunAfter(":frontend:clean", ":backend:clean")
I also tried replacing the second line with:
project("backend").build.mustRunAfter(":frontend:clean, ":backend:clean")
but still no luck.
I am still not sure why non of my tries work but here is a working approach:
task stage(dependsOn: [':frontend:clean', ':backend:clean', ':backend:build'])
tasks.getByPath(":backend:build").mustRunAfter(":frontend:clean", ":backend:clean")

In gradle, how can I run a task against all projects recursively from command line?

I'm looking for a syntax along the lines of ./gradlew :all:myTask that I can quickly execute from the command line. I must have missed it in the documentation somewhere.
I know I can modify the build to include a new task that runs a task against all sub-projects, however I'd prefer to not mess with modifying the build for simple one-off scenarios.
If I understand your goal correctly, running ./gradlew myTask should do what you want by default
:myTask
:foo:myTask
:foo:bar:myTask
:baz:myTask

Resources