Gradle Release Notes

Version 3.4-rc-3

The Gradle team is pleased to announce Gradle 3.4.

We're excited to bring you 3 incredible performance features in this release.

First up: Compile Avoidance. We've introduced a new mechanism for up-to-date checking of Java compilation that is sensitive to public API changes only. This means that if you change a comment or even a private API in a downstream project, Java compilation for upstream projects will be UP-TO-DATE.

Next: A stable incremental Java compiler. We've smartened the handling of constants, backed it with in-memory caches, and fixed many bugs. It is now production-ready for your build and has been promoted out of @Incubating.

Finally: A brand new Java Library Plugin. Use this when building a component intended to be used as a dependency from another project. It provides a strong separation between public (exported) and private code which not only gives great performance benefits (because consumers' compile classpaths are smaller) but also enforces architectural boundaries on the build level.

Put these together on our perf-enterprise-large benchmark Java project, and compilation time after a method body change is reduced from 2.5 minutes to 9 seconds! Let's put that in perspective:

perf-enterprise-large assemble

It is not just large projects that reap the benefits, for example the same use case for Apache Polygene was reduced from 14 seconds to 7 seconds.

Now, with your help and guidance we've been able to made a couple of highly-requested code-quality plugins improvements:

A special thank you to those who voted and contributed to these issues.

Last but not least, we've made it more convenient to let Gradle know when you want a build scan — just use --scan (or --no-scan if not). No need for the "magic" system property -Dscan anymore.

We hope you're able to build happiness with Gradle 3.4, and we look forward to your feedback via Twitter or on GitHub. Happy new year from the Gradle team!

Table Of Contents

New and noteworthy

Here are the new features introduced in this Gradle release.

Compile-avoidance for Java

This version of Gradle introduces a new mechanism for up-to-date checking of Java compilation that is sensitive to public API changes only.

If a dependent project has changed in an ABI-compatible way (only its private API has changed), then Java compilation tasks will now be up-to-date.

This means that if project A depends on project B and a class in B is changed in an ABI-compatible way (typically, changing only the body of a method), then Gradle won't recompile A. Even finer-grained compile-avoidance can be achieved by enabling incremental Java compilation, as explained below.

Some of the types of changes that do not affect the public API and are ignored:

Compile-avoidance can greatly improve incremental build time, as Gradle now avoids recompiling source files that will produce the same bytecode as the last time.

Compile-avoidance in the presence of annotation processors

Compile-avoidance is deactivated if annotation processors are found on the compile classpath, because for annotation processors the implementation details matter. To better separate these concerns, the CompileOptions for the JavaCompile task type now defines a annotationProcessorPath property.

If you are using annotation processors and want optimal performance, make sure to separate them from your compile classpath.

configurations {
    apt
}

dependencies {
    apt 'some.cool:annotation.processor:1.0'
}

tasks.withType(JavaCompile) {
    options.annotationProcessorPath = configurations.apt
}

Faster Java incremental compilation

The Java incremental compiler has been improved to deal with constants in a smarter way.

Due to the way constants are inlined by the Java compiler, previous Gradle releases have taken a conservative approach and recompiled all sources when a constant has changed. Now Gradle avoids recompiling under the following conditions:

The incremental compiler will recompile only a small subset of the potentially affected classes now.

In addition, the incremental compiler is more efficient and backed by in-memory caches, which avoids a lot of disk I/O that slowed it down in previous versions.

Stable Java incremental compilation

The Java incremental compiler is no longer incubating and is now considered stable. This Gradle release includes many bug fixes and improved performance for incremental Java compilation.

Note that incremental Java compilation is not enabled by default. It needs to be activated explicitly. We encourage all Gradle users to give it a try in their projects.

The Java Library plugin

The new Java Library plugin is the next step towards improved modeling of the Java ecosystem, and should be used whenever you are building a Java component aimed at being consumed by other components. This is typically called a library, and it has many advantages:

We strongly encourage users to migrate to this plugin, instead of the java plugin, whenever they are building a library. Some of the new configurations of this plugin are available to the java plugin too, and others are just deprecated.

@CompileClasspath annotation for task properties

Java compile-avoidance is implemented using a new @CompileClasspath annotation that can be attached to a task property, similar to the @InputFiles or @Classpath annotations.

This new annotation is also available for use in your own tasks as well, for those tasks that take a Java compile classpath. For example, you may have a task that performs static analysis using the signatures of classes. You can use the @CompileClasspath annotation for this task instead of @InputFiles or @Classpath, to avoid running the task when the class signatures have not changed.

Task for enforcing JaCoCo code coverage metrics

Gradle introduces a feature for the JaCoCo plugin strongly requested by the community: enforcing code coverage metrics. The JaCoCo plugin now provides a new task of type JacocoCoverageVerification enabling the user to define and enforce violation rules. Coverage verification does not automatically run as part of the check task. Please see the relevant user guide section on the “JaCoCo plugin” for more information.

tasks.withType(JacocoCoverageVerification) {
    violationRules {
        rule {
            limit {
                minimum = 0.5
            }
        }
    }
}

Gradle removes source set output directories on upgrade

Gradle keeps information about each task's inputs and outputs in your project's .gradle directory. If this information is lost or cannot be read, your build directory can be in an inconsistent state with stale files from previous builds. GitHub issue #1018 is an example of the problems this can cause.

Gradle now removes the output directories for source sets when this situation is detected. Most often, this occurs when performing a Gradle upgrade because the information kept in .gradle is not backwards compatible.

There are other situations where output files are not cleaned up, such as removing a sub project or a task from the build. You can follow the progress on GitHub issue #821.

Plugin library upgrades

The JaCoCo plugin has been upgraded to use JaCoCo version 0.7.8 by default.

Command line options for creating build scans

You can now create a build scan by using the --scan command line option. To explicitly disable creating a build scan, use the --no-scan command line option.

For more information about build scans, see https://gradle.com.

Improved feedback when skipping tasks with no source input

It is relatively common to have tasks within a build that can be skipped because they have no input source. For example, the standard java plugin creates a compileTestJava task to compile all java source at src/test/java. If at build time there are no source files in this directory the task can be skipped early, without invoking a Java compiler.

Previously in such scenarios Gradle would emit:

:compileTestJava UP-TO-DATE

This is now communicated as:

:compileTestJava NO-SOURCE

A task is said to have no source if all of its input file properties that are annotated with @SkipWhenEmpty are empty (i.e. no value or an empty set of files).

APIs that communicate that outcome of a task have been updated to accommodate this new outcome.
The TaskSkippedResult.getSkipMessage() of the Tooling API now returns NO-SOURCE for such tasks, where it previously returned UP-TO-DATE.
The TaskOutcome.NO_SOURCE enum value of TestKit is now returned for such tasks, where it previously returned TaskOutcome.UP_TO_DATE.

Deferred evaluation for WriteProperties task

The WriteProperties task that was introduced in Gradle 3.3 now supports deferred evaluation for properties:

Initial support for reproducible archives

When Gradle creates an archive, the order of the files in the archive is based on the order that Gradle visits each file. This means that even archive tasks with identical inputs can produce archives with different checksums. We have added initial support for reproducible archives, which tries to create an archive in a byte-for-byte equivalent manner.

For more information visit the section in the user guide about reproducible archives.

We would love to get feedback from you about this incubating feature!

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.

Incremental Java compilation

With the improvements made to the incremental Java compiler in this release, this is great time to promote this feature. If you want to make use of it, please keep in mind that it needs to be activated explicitly.

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.

Javadoc options should not be overwritten

Javadoc.setOptions(MinimalJavadocOptions) is now deprecated. Use Javadoc.options() to configure JavaDoc options.

JaCoCo class dump directory property renamed

JacocoTaskExtension.classDumpFile is now called classDumpDir and the old property is deprecated.

Potential breaking changes

WriteProperties task API

Skipping tasks with no source

Please see Improved feedback when skipping tasks with no source input.

Setting JavaDoc options

When the deprecated Javadoc.setOptions(MinimalJavadocOptions) method is called with a StandardJavadocDocletOptions, it replaces the task's own options value. When calling the method with a parameter that is not a StandardJavadocDocletOptions, only values declared by MinimalJavadocOptions will be copied.

compileOnly no longer extends compile

The fact that compileOnly extends the compile configuration was an oversight. It made it very hard for users to query for the dependencies that were actually "only used for compilation". With this release of Gradle, compileOnly no longer extends the compile configuration.

IDEA mapping has been simplified

The mapping from Gradle's configurations to IntelliJ IDEA's scopes has been drastically simplified. There used to be a lot of hardcoded mappings and pseudo-scopes in order to reduce the number of dependency declarations in the .iml files. These hardcoded mappings were intransparent to the user and added a lot of complexity to the codebase. Thus we decided to reimplement IDEA mapping with a very simple scheme:

This means that some runtime dependencies might be visible when using auto-completion in test classes. This felt like a small price to pay, since the same was already true for testRuntime dependencies.

We have thoroughly tested these new mappings and found them to work well. Nevertheless, if you encounter any problems importing projects into IDEA, please let us know.

runtimeClasspath used instead of runtime

When resolving the runtime classpath for Java applications, Gradle will now use the runtimeClasspath configuration instead of the runtime configuration. If you previously attached resolution rules to runtime, you should apply them to runtimeClasspath instead or apply them to all configurations.

Tooling providers should try not to depend on configurations directly, but use sourceSet.runtimeClasspath where applicable. This always contains the correct classpath for the current Gradle version and has been changed to return the runtimeClasspath configuration in this release. If you are directly resolving the runtime configuration, your tool will not work with the java-library plugin.

Configurations can be unresolvable

Since Gradle 3.3, configurations can be marked as not resolvable. If you or a plugin tries to resolve such a configuration, an IllegalStateException will be thrown. You can check whether a configuration is resolvable by calling Configuration#isCanBeResolved(). A configuration that cannot be resolved has a special meaning: it's often only there to declare dependencies only.

Although the concept had already been introduced in Gradle 3.3, the first release that comes with unresolvable configurations by default is Gradle 3.4. The Java and Java Library plugins add the following unresolvable configurations: "apiElements", "implementation", "runtimeElements", "runtimeOnly", "testImplementation", "testRuntimeOnly". The concept has been introduced in order to support variant aware dependency resolution.

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.

Erratum

In the Gradle 3.3 release, we accidentally left out the name of one of our contributors. We would like to recognize Sebastien Requiem for his contribution: - S3 repository can be configured to authenticate using AWS EC2 instance metadata (gradle/gradle#690).