Optimizing the build-edit-build loop
Gradle supports two types of task. One such type is the simple task, where you define the task with an action closure. We have seen these in Build Script Basics. For this type of task, the action closure determines the behaviour of the task. Cucumber-jvm with jUnit-4 runner can parallel tests. FYI current version of cucumber-jvm is 4.3.0. Execution failed for task '. In gradle.build file add jvmArgs to test task; #gradle.build.
In the past, we’ve recommended that you enable the Gradle Daemon (and parallel execution, with some caveats) to get the best performance out of Gradle. We’ve also talked about using incremental builds to speed up your build-edit-build feedback loop by skipping unnecessary work. Now there’s another optimization available—one that allows you to get out of the way and let Gradle start the build for you.
As of 2.5, Gradle supports continuous build execution, which will automatically re-execute builds when changes are detected to its inputs. There have been a few community plugins that add support for a Gradle “watch” mode that do something similar.
With Maven, the same watch functionality needs to be implemented for each plugin or you have to use a plugin that has a predefined set of goals. We wanted to do better than that. We wanted any plugin to be able to leverage the power of continuous builds without having to supply additional information. We also wanted the set of tasks to execute to be completely ad-hoc. Since Gradle needs to know a task’s inputs and outputs for incremental builds, we had all the information necessary to start watching for changes.
Using continuous build
Continuous build can be used with any task or set of tasks that have defined inputs and outputs. If you’re using well-behaved tasks, this shouldn’t be a problem for most builds. If you find that your build isn’t rebuilding with continuous build as you think it should, it could point to a problem in your build script.
Command-line option
You enable continuous build with the -t
or --continuous
command-line option along with whichever tasks you want to run (we call these task selectors). At least one task that runs needs to define inputs to enter continuous build mode.
For example, on a typical Java project,
would enable continuous build and re-run tests any time the main sources or test sources change.
We’re not limited to a single task, so we could also re-run tests and FindBugs on the main sources using
Determining when to run another build
When you run Gradle with the continuous build option, Gradle executes the build as usual, except Gradle also registers the inputs to all tasks with a file watch service. Even tasks that are UP-TO-DATE
will have their inputs recorded, so all inputs can be considered when triggering a new build. This means that you don’t have to start from a clean build for Gradle to know which inputs could change in continuous build mode.
After the end of the build, Gradle will start watching for file system changes based on the collected inputs. The Gradle command-line interface will display the message Waiting for changes to input files of tasks
on the console and will wait for changes to inputs. If any of the input files are changed or deleted, Gradle will execute another build with the identical set of task selectors. Gradle can detect changes to simple files (deleted, modified) and changes to directories (deleted or new files).
See a demo of this in action:
Exiting continuous build
Gradle Task Dependson
Once Gradle is running in continuous build, it will not exit, even if the build is not successful. To get out of continuous build, you should use Ctrl-D
to cancel the build. On Microsoft Windows, you must also press ENTER
or RETURN
after Ctrl-D
.
If you use Ctrl-C
, Gradle will exit abruptly and also kill the Gradle Daemon.
UPDATE: As of Gradle 3.1, Ctrl-C
no longer kills the Gradle Daemon.
Limitations
The User Guide chapter describes all limitations and quirks with continuous build.
Requires Java 7 or better
Gradle uses Java 7’s WatchService to watch for changes to inputs. This functionality is only available on JDK 7 or later.
Mac OS X performance
For GNU/Linux and Microsoft Windows, the file system change events are provided through a kernel service. For Mac OS X, Java falls back to a polling-based system. This means on Mac OS X only, change detection on a very, very large number of input files may be delayed and, in some cases, cause a deadlock. Both of these issues are tracked as JDK bugs: JDK-7133447 and JDK-8079620.
Changes to build scripts
Gradle doesn’t consider changes to your build logic when in continuous build mode. Build logic is created from build.gradle
, settings.gradle
, gradle.properties
and other sources. If you make changes to your build scripts, you’ll have to exit continuous build and restart Gradle. Future versions of Gradle will make it easier to describe inputs to your build logic so that continuous build can work with this as well.
Future improvements
In addition to mitigating some of the limitations with the current implementation, there are other interesting things we can use continuous build to accomplish.
Right now, there are not any supported, public ways of managing a process started by Gradle that needs to exist between builds. Gradle expects that a process started (e.g., via Exec
) will exit as part of the build.
In the next release (2.6), Play support is coming to Gradle, and with that you’ll be able to start Play applications in a separate JVM for local development. With continuous build enabled, Gradle will hot-reload the Play application whenever classes or assets are changed. The Play plugin accomplishes this by registering the Play JVM with Gradle in a way that survives between builds.
Gradle Task Execute Command Line
We want to eventually evolve this Play specific reload functionality into a general feature, so plugins can have their own “hot-reload”-like behavior.
Another opportunity for improvement is up-to-date checking. For very large projects, up-to-date checking can be time consuming for the no-op case. When looking for out-of-date files, Gradle must scan entire directories or recalculate file checksums. When using continuous build, Gradle must already keep track of file and directory changes, so in some cases, Gradle may be able to skip checks for files that are known to have not changed.
Feedback
Please let us know on the forums if you run into any surprises with this new feature.
Related Posts
- ❯ Introducing Java toolchains
- ❯ Introducing Configuration Caching
- ❯ Introducing file system watching