Gradle Release Notes

Version 4.0

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.

grouped logging

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.

4.0 console

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 PropertyStates 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.

Table Of Contents

New and noteworthy

Here are the new features introduced in this Gradle release.

Parallel download of dependencies

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.

Build cache improvements

Remote build cache honors --offline

When running with --offline, Gradle will disable the remote build cache.

Detecting overlapping task outputs

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.

Stricter validation of task properties

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:

  • a task has a property without an input or output annotation (this might indicate a forgotten input or output),
  • a task has @Input on a File property (instead of using @InputFile of @InputDirectory),
  • a task declares conflicting types for a property (say, both @InputFile and @InputDirectory),
  • a cacheable task declares a property without specifying @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.

Cache-safe mixed JVM language compilation

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.

Automatic clean-up of local build cache

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.

Improved tracking of additional task actions

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.

Public type for representing lazily evaluated properties

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()
        }
    }
}

Configurable input normalization: Ignore runtime classpath resources for up-to-date checks and the build cache

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.

Convenience method for adding Google repository

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()
}

User experience improvements

Logs grouped by project and task

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.

Default logging reduced

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.

Parallel console

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.

Better modeling of tasks that delete files

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.

Checkstyle configuration directory conventions

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.

Default Zinc compiler upgraded from 0.3.7 to 0.3.13

This will take advantage of performance optimizations in the latest Zinc releases.

Ivy plugin repositories support patterns and layouts

Ivy plugin repositories now support the same API for patterns and layouts that Ivy artifact repositories support.

Track Java version for Groovy compilation

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.

Configure log level using Gradle properties

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.

Fixed issues

Deprecations

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.

Setting the compiler executable is no longer deprecated

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.

Deprecated APIs

Potential breaking changes

Build Scan 1.7.4 or newer is required when used with Gradle 4.0

To support additional features, you must use Build Scan 1.7.4 or newer with Gradle 4.0.

Multiple class directories for a single source set

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.

Detecting test classes for custom Test tasks

Before 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

Location of classes in the build directory

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().

maven-publish and ivy-publish mirror multi-project behavior

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.

Memory settings not tracked as inputs for JVM compilation

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.

Groovy upgraded to 2.4.11

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.

Version of PMD has been upgraded

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'
}

Changes to previously deprecated APIs

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.

Adding copy specs is not allowed during task execution of a AbstractCopyTask task

You 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"
        }
    }
}

Changes to how build cache configurations are described

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); } }

Changes to IDE plugins

Changes to dependency ordering

Several changes have been made to the way that Gradle orders files in the dependency resolution results:

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.

External contributions

We would like to thank the following community members for making contributions to this release of Gradle.

We love getting contributions from the Gradle community. For information on contributing, please see gradle.org/contribute.

Known issues

Known issues are problems that were discovered post release that are directly related to changes made in this release.