Gradle Release Notes

Version 7.6

The Gradle team is excited to announce Gradle 7.6.

This release includes building and running code with Java 19, a flag to rerun tasks individually, a new strongly-typed dependencies block for JVM test suites, and a pluggable system for Java Toolchains provisioning.

As always there are also performance improvements like enhancements to the configuration cache and incremental compilation.

We would like to thank the following community members for their contributions to this release of Gradle: altrisi, aSemy, Ashwin Pankaj, Aurimas, BJ Hargrave, Björn Kautler, Bradley Turek, Craig Andrews, Daniel Lin, David Morris, Edmund Mok, Frosty-J, Gabriel Feo, Ivan Gavrilovic, Jendrik Johannes, John, Joseph Woolf, Karl-Michael Schindler, Konstantin Gribov, Leonardo Brondani Schenkel, Martin d'Anjou, Michael Bailey, Pete Bentley, Rob Bavey, Sam Snyder, sll552, teawithbrownsugar, Thomas Broadley, urdak, Varun Sharma, Xin Wang

Table Of Contents

Upgrade instructions

Switch your build to use Gradle 7.6 by updating your wrapper:

./gradlew wrapper --gradle-version=7.6

See the Gradle 7.x upgrade guide to learn about deprecations, breaking changes and other considerations when upgrading to Gradle 7.6.

For Java, Groovy, Kotlin and Android compatibility, see the full compatibility notes.

New features and usability improvements

JVM

Added Support for Java 19

Gradle 7.6 supports compiling, testing and running on Java 19.

Introduced strongly-typed dependencies block for JVM test suites

The JVM test suite dependencies block now uses a strongly-typed API. This makes the build logic cleaner and improves assistance in the IDEs, especially with the Kotlin DSL.

Previously, the JVM test suite dependencies block only accepted dependencies of type Object.

testing {
    suites {
        val test by getting(JvmTestSuite::class) {
            useJUnitJupiter()
            dependencies {
                implementation(project(":foo")) {
                    // Receiver (this) is of type Dependency
                    // To access ProjectDependency
                    // methods, smart-cast:
                    this as ProjectDependency
                    // Now available as a ProjectDependency
                    println(dependencyProject)
                }
            }
        }
    }
}

Now, each notation provides its Dependency subtype:

testing {
    suites {
        val test by getting(JvmTestSuite::class) {
            useJUnitJupiter()
            dependencies {
                implementation(project(":foo")) {
                    // `this` already of type ProjectDependency
                    println(dependencyProject)
                }
            }
        }
    }
}

For example, using a String provides an ExternalModuleDependency. Using a FileCollection provides a FileCollectionDependency. This allows Java and Kotlin to properly configure all types of dependencies and improves IDE support for the Groovy DSL.

In addition, the Kotlin DSL now supports named arguments for external dependencies in this block:

testing {
    suites {
        "test"(JvmTestSuite::class) { 
            useJUnitJupiter()
            dependencies {
                implementation(module(group = "com.google.guava",
                               name = "guava",
                               version = "31.1-jre"))
            }
        }
    }
}

For more information about the test suite dependencies block, see Differences Between Test Suite and Top-Level Dependencies.

Added support for Java Toolchain downloads from arbitrary repositories

Starting in Gradle 7.6, Gradle can download JVM toolchains from arbitrary repositories. By default, Gradle downloads toolchains from Adoptium/AdoptOpenJDK. You can now override the default providers with repositories of your choice using a toolchain resolver plugin.

For example, the following uses custom plugins that provide AzulResolver and AdoptiumResolver to add custom toolchains for Adoptium and Azul:

toolchainManagement {
    jvm {
        javaRepositories {
            repository("azul") {
                resolverClass.set(AzulResolver::class.java)
                credentials {
                    username = "user"
                    password = "password"
                }
                authentication {
                    create<DigestAuthentication>("digest")
                }
            }
            repository("adoptium") {
                resolverClass.set(AdoptiumResolver::class.java)
            }
        }
    }
}

For more information about using custom toolchain resolvers, see the Toolchain Download Repositories documentation. For more information about writing custom toolchain resolvers, see the Toolchain Resolver Plugins documentation.

Added support for incremental compilation following a compilation failure

Gradle supports Java incremental compilation by default and Groovy incremental compilation as an opt-in experimental feature.

In previous versions, a compilation failure caused the next compilation to perform a full recompile. Starting in Gradle 7.6, Java and Groovy incremental compilation can work even after a failure.

This feature is enabled by default when incremental compilation is enabled. The feature can be disabled with the incrementalAfterFailure compile option.

Introduced support for Java 9+ network debugging

You can run a Java test or application child process with debugging options to accept debugger client connections over the network. If the debugging options only specify a port, but not a host address, the set of accepted connections depends on your version of Java:

This release adds a new property to JavaDebugOptions: host. This allows you to specify the debugger host address along with the port.

Similarly, the new Gradle property org.gradle.debug.host now enables running the Gradle process with the debugger server accepting connections via network on Java 9 and above.

On Java 9 and above, use the special host address value * to make the debugger server listen on all network interfaces. Otherwise, use the address of one of the machine's network interfaces.

Revised dependencies generated from init Maven conversions from implementation to api

The init task now adds compile-time Maven dependencies to Gradle's api configuration when converting a Maven project. This sharply reduces the number of compilation errors. It is still recommended to use implementation where possible.

For more information about Maven conversions, see the Build Init Plugin.

General Improvements

Introduced flag for individual task rerun

All tasks can now use the --rerun option. This option works like --rerun-tasks, except --rerun only affects a single task. For example, you can force tests to ignore up-to-date checks like this:

gradle test --rerun

For more information about the rerun option, see Built-in Task Options.

Relocated convention plugins in projects generated with init

🐣 This feature is incubating.

When generating builds with the init task and opting in to incubating features, Gradle now places convention plugins under the build-logic directory instead of in buildSrc.

Convention plugins are Gradle’s recommended way of organizing build logic where you can compose custom build logic by applying and configuring both core and external plugins.

For more information about convention plugins, see Convention Plugins.

Introduced network timeout configuration for wrapper download

It is now possible to configure the network timeout for downloading Gradle wrapper files. The default value is 10000ms and can be changed in several ways:

From the command line:

$ ./gradlew wrapper --network-timeout=30000

In your build scripts or convention plugins:

tasks.wrapper {
    networkTimeout.set(30000)
}

Or in gradle/wrapper/gradle-wrapper.properties:

networkTimeout=30000

For more information about the Gradle wrapper, see Gradle Wrapper.

Introduced ability to explain why a task was skipped with a message

You can now provide a reason message when conditionally disabling a task using the Task.onlyIf predicate:

tasks.register("slowBenchmark") {
    onlyIf("slow benchmarks not enabled") {
        false
    }
}

Gradle outputs reason messages at log level INFO. To output reason messages to the console, use the --info or --debug log levels.

Dependency Management

Clarified the ordering of disambiguation rule checks in resolvableConfigurations reports

Attribute disambiguation rules control the variant of a dependency selected by Gradle when:

Attribute disambiguation rules select a single matching dependency variant in such cases. The resolvableConfigurations reporting task now prints the order of these rules:

$ ./gradlew resolvableConfigurations
--------------------------------------------------
Disambiguation Rules
--------------------------------------------------
The following Attributes have disambiguation rules defined.

    - flavor
    - org.gradle.category (1)
    - org.gradle.dependency.bundling (5)
    - org.gradle.jvm.environment (6)
    - org.gradle.jvm.version (3)
    - org.gradle.libraryelements (4)
    - org.gradle.plugin.api-version
    - org.gradle.usage (2)

(#): Attribute disambiguation precedence

For more information, see Attribute Disambiguation Rules.

Configuration Cache

The configuration cache improves build time by caching the result of the configuration phase and reusing this for subsequent builds.

Improved configuration cache failure recovery

In previous Gradle versions, it was possible to leave a configuration cache entry in a permanently broken state after a dependency resolution failure. Following builds would simply reproduce the failure without any attempt to recover from it.

Starting with Gradle 7.6, this is no longer the case. Gradle recovers from dependency resolution failures in exactly the same way whether the configuration cache is enabled or not.

Extended configuration cache task compatibility

The dependencies, buildEnvironment, projects and properties tasks are now compatible with the configuration cache.

Added configuration cache support to the Maven Publish Plugin

The Maven Publish Plugin is now compatible with the configuration cache.

Note that when using credentials, the configuration cache requires safe credential containers.

Improved handling of --offline option

Gradle now stores configuration caches for online and offline modes separately. This change supports builds and plugins that need to behave differently during configuration depending on whether the --offline option is in effect.

For more information, see the --offline CLI option.

Plugin Development

Introduced support for task options of type Integer

You can now pass integer task options declared as Property<Integer> from the command line.

For example, the following task option:

@Option(option = "integer-option", description = "description")
public abstract Property<Integer> getIntegerOption();

can be passed from the command line as follows:

gradle myCustomTask --integer-option=123

IDE Integration

These improvements are for IDE integrators and are not directly for end-users until their specific IDE implements the integration.

Enhanced test events to distinguish between assertion and framework failures

Gradle 7.6 introduces new failure types for the Failure interface returned by FailureResult.getFailures(): TestAssertionFailure and TestFrameworkFailure. IDEs can now distinguish between assertion and framework failures using progress event listeners. For test frameworks that expose expected and actual values, TestAssertionFailure contains those values.

Introduced TestLauncher task execution

The TestLauncher interface now allows Tooling API clients to execute any tasks along with the selected tests:

ProjectConnection connection = ...
connection.newTestLauncher()
          .withTaskAndTestClasses("integTest", ["org.MyTest"])
          .forTasks("startDB")
          .run()

Introduced class, method, package, and pattern test selection via TestLauncher

The TestLauncher interface now allows Tooling API clients to select test classes, methods, packages and patterns with a new API.

TestLauncher testLauncher = projectConnection.newTestLauncher();
testLauncher.withTestsFor(spec -> {
    spec.forTaskPath(":test")
        .includePackage("org.pkg")
        .includeClass("com.TestClass")
        .includeMethod("com.TestClass")
        .includePattern("io.*")
}).run();

Added support for passing system properties to the build with the Tooling API

Before 7.6, the Tooling API started builds with the system properties from the host JVM. This leaked configuration from the IDE to the build. Starting in Gradle 7.6, LongRunningOperation.withSystemProperties(Map) provides an isolated set of build system properties. For more information, see LongRunningOperation.

Promoted features are features that were incubating in previous versions of Gradle but are now supported and subject to backwards compatibility. See the User Manual section on the “Feature Lifecycle” for more information.

This Gradle release promotes the following features to stable:

Fixed issues

Known issues

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

External contributions

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

Reporting problems

If you find a problem with this release, please file a bug on GitHub Issues adhering to our issue guidelines. If you're not sure you're encountering a bug, please use the forum.

We hope you will build happiness with Gradle, and we look forward to your feedback via Twitter or on GitHub.