The Gradle team is pleased to announce Gradle 4.0.
We are excited to share some great new features and improvements with you in this release:
First and foremost, Gradle's Build Cache is now production-ready for Java and Groovy compilation and Java test tasks! This provides remarkable performance, making Gradle builds up to 100x faster than Maven in common scenarios. This is further improved by overlapping outputs detection, configurable classpath normalization that avoids unnecessary task execution, and more listed in the full release notes. The cacheability of other tasks, including other languages, will be completed in future releases. We invite you to check out our new guide for maximizing effectiveness of the Gradle Build Cache.
Now on to user experience: this release has a number of enhancements in logging and terminal display. Log output is now grouped by project and task when attached to a terminal — output from tasks run in parallel will no longer be interleaved. However, logging behaves the same as previous Gradle versions in non-interactive environments, and with --console=plain
, to allow automated tools like CI systems to parse the logs they expect.
The console output now shows more detail about what exactly is in-progress, and parallel work in-progress is now displayed by default. You can learn more about logging and console output in the user guide.
Speaking of parallel work-in-progress, artifacts and metadata from remote repositories are now downloaded in parallel! Gradle also avoids downloading the same dependency twice even if parallel tasks request the same one simultaneously.
Gradle Script Kotlin v0.9.0 (included in this release) brings very welcome improvements: auto-detection of Kotlin build scripts, default imports for the whole Gradle API, improved samples and docs with an API reference, better IntelliJ experience and more!
Finally, this release introduces a public type that represents lazily-evaluated properties (aka ConventionMapping
). This is one of the most-requested features by plugin authors. You can learn more about PropertyState
s here. A good example of their usage can be found in the gradle-site-plugin.
We hope you will build happiness with Gradle 4.0, and we look forward to your feedback via Twitter or on GitHub.
Test
tasksAbstractCopyTask
taskHere are the new features introduced in this Gradle release.
Gradle will now download dependencies from remote repositories in parallel (both metadata and artifacts). It will also make sure that if you build multiple projects in parallel (with --parallel
) and that 2 projects try to download the same dependency at the same time, that dependency will not be downloaded twice. This is complemented very well by the improved console output that shows parallel downloads.
--offline
When running with --offline
, Gradle will disable the remote build cache.
When two tasks write into the same directory, Gradle will now disable task output caching for the second task to execute. This prevents issues where task outputs for a different task are captured for the wrong build cache key. On subsequent builds, if overlapping outputs are detected, Gradle will also prevent you from loading task outputs from the cache if it would remove existing outputs from another task.
You can diagnose overlapping task output issues by running Gradle at the --info
log level. If you are using Gradle Build Scans, the same detailed reason for disabling task output caching will be included in the build timeline.
When a plugin is built with the Java Gradle Plugin Development Plugin, custom task types declared in the plugin will go through validation. In Gradle 4.0, additional problems are now detected.
A warning is shown when:
@Input
on a File
property (instead of using @InputFile
of @InputDirectory
),@InputFile
and @InputDirectory
),@PathSensitive
. In such a case, we default to ABSOLUTE
path sensitivity, which will prevent the task's outputs from being shared across different users via a shared cache.For more info on using task property annotations, see the user guide chapter.
In Gradle 3.5, projects that used both Java and another JVM language (like Groovy or Scala) would encounter problems when using the build cache. The class files created by multiple compilation tasks were all placed into the same output directory, which made determining the set of outputs to cache for each task difficult and would cause Gradle to cache the wrong outputs for each compilation task.
Gradle now uses separate output directories for each JVM language.
By default, Gradle limits the size of the local build cache to 5GB. In Gradle 3.5, the local build cache was allowed to grow indefinitely.
You can increase or decrease the size of the local build cache by configuring your local cache:
buildCache {
local {
// Set target size to 10GB
targetSizeInMB = 10240
}
}
This is a target size for the build cache. Gradle will periodically check if the local build cache has grown too large and trim it to below the target size. The least recently used build cache entries will be deleted first.
When computing the build cache key for a task, Gradle takes into account all the inputs of the task. These inputs included the class name and the full classpath of the task's type since 3.0. However, Gradle was not tracking the implementation of additional actions attached to the task via doFirst
and doLast
.
Due to this, Gradle 3.5 and before would reuse the result of the first
task for the second
task:
task first {
outputs.cacheIf { true }
outputs.file file("first.txt")
doFirst {
file("first.txt").text = "Hello from the first task"
}
}
task second {
outputs.cacheIf { true }
outputs.file file("second.txt")
doFirst {
file("second.txt").text = "Hello from the second task"
}
}
Gradle 4.0 recognizes the two doFirst
actions to be different, and will not reuse cached results between first
and second
.
Because Gradle's build lifecycle clearly distinguishes between configuration phase and execution phase the evaluation of property values has to be deferred under certain conditions to properly capture end user input. A typical use case is the mapping of extension properties to custom task properties as part of a plugin implementation. In the past, many plugin developers were forced to solve evaluation order problems by using the concept of convention mapping, an internal API in Gradle subject to change.
This release of Gradle introduces a mutable type to the public API representing a property with state. The relevant interface is called PropertyState
. An instance of this type can be created through the method Project.property(Class)
.
The following example demonstrates how to use the property state API to map an extension property to a custom task property without running into evaluation ordering issues:
apply plugin: GreetingPlugin
greeting {
message = 'Hi from Gradle'
outputFiles = files('a.txt', 'b.txt')
}
class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
// Add the 'greeting' extension object
def extension = project.extensions.create('greeting', GreetingPluginExtension, project)
// Add a task that uses the configuration
project.tasks.create('hello', Greeting) {
message = extension.messageProvider
outputFiles = extension.outputFiles
}
}
}
class GreetingPluginExtension {
final PropertyState<String> message
final ConfigurableFileCollection outputFiles
GreetingPluginExtension(Project project) {
message = project.property(String)
setMessage('Hello from GreetingPlugin')
outputFiles = project.files()
}
String getMessage() {
message.get()
}
Provider<String> getMessageProvider() {
message
}
void setMessage(String message) {
this.message.set(message)
}
FileCollection getOutputFiles() {
outputFiles
}
void setOutputFiles(FileCollection outputFiles) {
this.outputFiles.setFrom(outputFiles)
}
}
class Greeting extends DefaultTask {
final PropertyState<String> message = project.property(String)
final ConfigurableFileCollection outputFiles = project.files()
@Input
String getMessage() {
message.get()
}
void setMessage(String message) {
this.message.set(message)
}
void setMessage(Provider<String> message) {
this.message.set(message)
}
FileCollection getOutputFiles() {
outputFiles
}
void setOutputFiles(FileCollection outputFiles) {
this.outputFiles.setFrom(outputFiles)
}
@TaskAction
void printMessage() {
getOutputFiles().each {
it.text = getMessage()
}
}
}
Gradle 4.0 supports ignoring particular resources on a runtime classpath. This affects up-to-date checks and the calculation of build cache keys.
It's common for a project to have a file that contains volatile data that frequently changes without affecting runtime behavior. This information can be used to audit artifacts, identify the CI job that published the artifact or identify when an artifact was produced.
Including files like this on your runtime classpath can cause tasks like the test
task to never be up-to-date or cause build cache misses since every build can have a different build cache key.
It is now possible to tell Gradle about these files by configuring project level input normalization:
normalization {
runtimeClasspath {
ignore 'build-info.properties'
}
}
This configuration tells Gradle to ignore changes to files named build-info.properties
on the runtime classpath. Please note that this will not affect the runtime classpath that the Test
task will use. In other words, any test is still free to load build-info.properties
as it is still available on the classpath.
For more information about this feature, see the corresponding section in the user guide.
A convenience method for the Google repository was added to RepositoryHandler
.
You can now add Google's Maven repository to your build to resolve Android Support Library dependencies instead of downloading them from the Android SDK Manager. The following example demonstrates using the new shortcut repository declaration:
repositories {
google()
}
Parallel execution causes logs from simultaneous tasks to be interleaved, rendering them less useful. Gradle 4.0 buffers output by project and task and flushes upon completion or every few seconds for long-running tasks.
Gradle sometimes outputs very verbose logs in mid-to-large sized projects, which makes it far too easy to miss the logs you actually want to act on. Output is nearly identical to previous releases when not attached to a terminal or using --console=plain
to allow users or CI systems to parse logs as they always have. We recommend the use of build scans, --info
, or a plain console for granular task outcomes information.
The terminal display of work in-progress now shows parallel work by default, and will adjust to parallel tasks added, growing as needed up to one-half the height of the attached console. This is not displayed in non-interactive environments.
A task can now annotate properties with @Destroys
to explicitly model that a task deletes a file or collection of files.
class RemoveTempDirs extends DefaultTask {
@Destroys
FileCollection tempDirs
@TaskAction
void removeDirs() {
project.delete(tempDirs)
}
}
A task can also programmatically declare files it will delete using the API on Task.getDestroyables()
.
By explicitly modeling the files that a task deletes, this allows Gradle to take this information into account when selecting tasks to execute from the task graph while running with --parallel
. Gradle can use this information to avoid starting a deletion task when:
Conversely, Gradle will also avoid starting tasks that create or consume a set of files while a deletion task that removes those files is currently running.
The Delete
task automatically uses the @Destroys
annotation, so any files added via its delete()
API will be safe when running in parallel. For instance, it is safe to run clean build
or build clean
while using --parallel
now.
To read more about this feature, see the userguide section on Incremental Build.
If you use additional configuration files with Checkstyle, like suppressions.xml
, these files need to be specified with an absolute path. Most projects use a variable like config_loc
to build the path to these configuration files.
Gradle now defines a config_loc
property that can be used in your checkstyle.xml
. See the user guide for more information.
This change makes Checkstyle build cache friendly, so that your build does not need to depend on machine-specific paths and is more likely to keep track of all inputs to the Checkstyle
task.
This will take advantage of performance optimizations in the latest Zinc releases.
Ivy plugin repositories now support the same API for patterns and layouts that Ivy artifact repositories support.
The Java version used by Groovy compilation influences the compiled Groovy and Java classes for the GroovyCompile
task. Gradle now tracks changes to this version and recompiles whenever necessary.
Gradle now allows you to specify the log level as a Gradle property: org.gradle.logging.level
. Allowed values are quiet
, warn
, lifecycle
(default), info
, and debug
. This allows a default log level to be set for a project, a machine, etc. See the user guide for more information.
Promoted features are features that were incubating in previous versions of Gradle but are now supported and subject to backwards compatibility. See the User guide section on the “Feature Lifecycle” for more information.
The following are the features that have been promoted in this Gradle release.
Features that have become superseded or irrelevant due to the natural evolution of Gradle become deprecated, and scheduled to be removed in the next major Gradle version (Gradle 4.0). See the User guide section on the “Feature Lifecycle” for more information.
The following are the newly deprecated items in this Gradle release. If you have concerns about a deprecation, please raise it via the Gradle Forums.
In Gradle 3.5 ForkOptions.executable
has been deprecated. In Gradle 4.0 it is not deprecated anymore, but using it to fork a compiler will disable task output caching for the compile task.
JDepend
File getClassesDir()
- Use FileCollection getClassesDirs()
setClassesDir(File)
- Use setClassesDirs(FileCollection)
Test
File getTestClassesDir()
- Use FileCollection getTestClassesDirs()
setTestClassesDir(File)
- Use setTestClassesDirs(FileCollection)
SourceSetOutput
File getClassesDir()
- Use FileCollection getClassesDirs()
or SourceDirectorySet.getOutputDir()
setClassesDir(File)
- Use SourceDirectorySet.setOutputDir(File)
To support additional features, you must use Build Scan 1.7.4 or newer with Gradle 4.0.
In projects that use multiple JVM languages (Java and Scala, Groovy and other languages) in separate source directories (e.g., src/main/groovy
and src/main/java
), Gradle now uses separate output directories for each language.
To return to the old behavior, explicitly set the classes directory:
// Change the output directory for the main source set back to the old path
sourceSets.main.output.classesDir = new File(buildDir, "classes/main")
Please be aware that this will interfere with the effectiveness of the build cache when using multiple JVM languages in the same source set. Gradle will disable caching for tasks when it detects that multiple tasks create outputs in the same location.
Test
tasksBefore Gradle 4.0, all test classes were compiled into a single output directory. As described above, Gradle now uses separate classes directories for each language in a source set.
Builds that define custom Test
tasks may not find the same test classes due to these changes if tests are written in languages other than Java. Deprecation warnings warn about this behavior. Test classes that were found in previous versions of Gradle may not run until the deprecation message is fixed.
Instead of configuring a single path for testClassesDir
, you must now configure a collection of paths with testClassesDirs
. A sample is provided in the Test
[javadoc](javadoc/org/gradle/api/tasks/testing/Test.html#setTestClassesDirs(org.gradle.api.file.FileCollection)).
This found all "integrationTest" classes before 4.0:
integrationTest.testClassesDir = sourceSets.integrationTest.output.classesDir
This is required for 4.0 and going forward:
integrationTest.testClassesDirs = sourceSets.integrationTest.output.classesDirs
The default location of classes when using the java
, groovy
or scala
plugin has changed from:
Java, `src/main/java` -> build/classes/main
Groovy, `src/main/groovy` -> build/classes/main
Scala, `src/main/scala` -> build/classes/main
Generically, `src/main/${sourceDirectorySet.name}` -> build/classes/${sourceSet.name}
to
Java, `src/main/java` -> build/classes/java/main
Groovy, `src/main/groovy` -> build/classes/groovy/main
Scala, `src/main/scala` -> build/classes/scala/main
Generically, `src/main/${sourceDirectorySet.name}` -> build/classes/${sourceDirectorySet.name}/${sourceSet.name}
Some compilers, like the Groovy and Scala compilers, support Java compilation as well. Java files compiled by these tools will be written into the output directory of that language, not in the Java classes directory.
Plugins, tasks or builds that used hardcoded paths may fail. You can access the specific output directory for a particular language via SourceDirectorySet#outputDir
or the collection of all of the output directories with SourceSetOutput#getClassesDirs()
.
When using the java
plugin, all compile
and runtime
dependencies will now be mapped to the compile
scope, i.e. "leaked" into the consumer's compile classpath. This is in line with how these legacy configurations work in multi-project builds. We strongly encourage you to use the api
(java-library plugin only), implementation
and runtimeOnly
configurations instead. These are mapped as expected, with api
being exposed to the consumer's compile classpath and implementation
and runtimeOnly
only available on the consumer's runtime classpath.
Previously Gradle would treat JVM compilation tasks as out-of-date whenever their memory settings changed compared to the previous execution. Since Gradle 4.0, these parameters are not treated as inputs anymore, and thus the compilation tasks will stay up-to-date when they are changed.
The version of Groovy bundled with Gradle was changed from Groovy 2.4.10 to Groovy 2.4.11.
This release fixes several issues where Groovy compilation could produce different (but functionally equivalent) bytecode given the same source files due to nondeterministic ordering in the compiler. These problems could cause build cache misses in Gradle 3.5 when compiling Groovy and Gradle script sources.
By default, Gradle now uses PMD 5.6.1. Previously, Gradle used PMD 5.5.1.
Newer versions of PMD usually bring new rules, better inspections and bug fixes. Your build may fail due to these changes.
You can upgrade or downgrade the version of PMD with:
pmd {
toolVersion = '5.5.1'
}
JacocoPluginExtension
methods getLogger()
, setLogger(Logger)
are removed.JacocoTaskExtension
methods getClassDumpFile()
, setClassDumpFile(File)
, getAgent()
and setAgent(JacocoAgentJar)
are removed.AccessRule(Object, Object)
.ProjectDependency(String, String)
and the methods getGradlePath()
, setGradlePath(String)
.WbDependentModule(Object)
.WbProperty(Object)
.WbResource(Object)
.JarDirectory(Object, Object)
.Jdk(Object, Object, Object, Object)
.ModuleDependency(Object, Object)
.RhinoWorkerHandleFactory
and RhinoWorkerUtils
into internal package.RhinoWorker
.EarPluginConvention(Instantiator)
.registerWatchPoints(FileSystemSubset.Builder)
from FileCollectionDependency
.getConfiguration()
from ModuleDependency
.getProjectConfiguration()
from ProjectDependency
.org.gradle.caching.BuildCache
.org.gradle.caching.MapBasedBuildCache
.@OrderSensitive
and the method TaskInputFilePropertyBuilder.orderSensitive
.dependencyCacheDir
with getter and setters in java plugin, JavaPluginConvention
, and CompileOptions
(commit edadbed1)AntDepend
,
AntDependsStaleClassCleaner
, and
DependOptions
Javadoc#setOptions
Manifest.writeTo(Writer)
. Please use Manifest.writeTo(Object)
TaskInputs.source()
and sourceDir()
. Please use TaskInputs.file().skipWhenEmpty()
, files().skipWhenEmpty()
and dir().skipWhenEmpty()
.TaskInputs.file()
, files()
, dir()
and TaskOutputs.file()
, files()
and dir()
are not supported anymore.TaskOutputs.doNotCacheIf(Spec)
, use doNotCacheIf(String, Spec)
instead.ValidateTaskProperties.classesDir
, use ValidateTaskProperties.classes
.The deprecated jetty
plugin has been removed. We recommend using the Gretty plugin for developing Java web applications. The deprecated pluginRepositories
block for declaring custom plugin repositories has been removed in favor of pluginManagement.repositories
.
AbstractCopyTask
taskYou can no longer add copy specs to a copy (like Copy
and Sync
) or archive task (like Zip
and Tar
) when the task is executing. Tasks that used this behavior could produce incorrect results and not honor task dependencies.
Starting with Gradle 4.0, builds that rely on this behavior will fail. Previously, Gradle only failed if the task was cacheable and emitted a warning otherwise.
// This task adds a copy spec during the execution phase.
task copy(type: Copy) {
from ("some-dir")
into ("build/output")
doFirst {
// Adding copy specs during runtime is not allowed anymore
// The build will fail with 4.0
from ("some-other-dir") {
exclude "non-existent-file"
}
}
}
The (incubating) BuildCacheServiceFactory
and BuildCacheService
interfaces have changed in this release. This only affects custom build cache connector implementations. It does not affect usage of the build cache connectors that ship with Gradle.
Previously, the BuildCacheService
was responsible for providing a getDescription()
method that returned a human friendly description of the cache. This responsibility has been moved to the associated BuildCacheServiceFactory
implementation, that now receives a Describer
parameter. The custom service factory can use this to declare the type of the service and configuration parameters that are relevant to the build cache connector being created. getDescription()
has been removed.
An example of the factory method used to create a custom build cache connector with a BuildCacheServiceFactory
:
java public class InMemoryBuildCacheServiceFactory implements BuildCacheServiceFactory<InMemoryBuildCache> { @Override public BuildCacheService createBuildCacheService(InMemoryBuildCache config, Describer describer) { int maxSize = config.getMaxSize(); describer.type("in-memory").config("size", String.valueOf(maxSize)); return new InMemoryBuildCacheService(maxSize); } }
EclipsePlugin
and IdeaPlugin
. Note that these types are not designed to be directly instantiated.EclipsePlugin.performPostEvaluationActions()
and IdeaPlugin.performPostEvaluationActions()
. Post-evaluation actions are no longer used.Several changes have been made to the way that Gradle orders files in the dependency resolution results:
gradleApi()
are now ordered in the same way as other dependencies, in consumer first order. In previous Gradle versions these dependencies were always added at the start of the result.Beyond this, Gradle does not make any other guarantees about the ordering of files. However, file order is always the same for a given dependency graph.
We would like to thank the following community members for making contributions to this release of Gradle.
FileReferenceFactory.toString()
(gradle/gradle#1440)@DelegatesTo
and @ClosureParams
to Project
(gradle/gradle#930)We love getting contributions from the Gradle community. For information on contributing, please see gradle.org/contribute.
Known issues are problems that were discovered post release that are directly related to changes made in this release.