Gradle Release Notes

Version 2.8-rc-1

Gradle 2.8 delivers performance improvements and a collection of general fixes and enhancments.

Large builds with many source files should see major improvements in incremental build speed. This release also brings faster build script compilation, faster source compilation when using the new continuous mode, and general performance improvements that apply to all builds.

Building upon the recent releases, this release brings more improvements to the new Gradle TestKit. It is now easier to inject plugins under test into test builds.

Work continues on the new "managed model". This release brings richer modelling capabilities along with interoperability improvements when dynamically depending on rule based tasks.

A Gradle release would not be complete without contributions from the wonderful Gradle community. This release provides support for file name encoding in Zip files, support for more PMD features and other fixes from community pull requests.

Table Of Contents

New and noteworthy

Here are the new features introduced in this Gradle release.

Faster incremental builds

One of Gradle's key features is the ability to perform “incremental builds”. This allows Gradle to avoid doing redundant work, by detecting that it can safely reuse files created by a previous build. For example, the “class files” created by the Java compiler can be reused if there were no changes to source code or compiler settings since the previous build. This is a generic capability available to all kinds of work performed by Gradle.

This feature relies on tracking checksums of files in order to detect changes. In this Gradle release, improvements have been made to the management of file checksums, resulting in significantly improved build times when the build is mostly up to date (i.e. many previously created files were able to be reused).

Highly incremental builds of projects with greater than 140,000 files have been measured at 35-50% faster with Gradle 2.8. Very large projects (greater than 400,000 files) are also significantly faster again, if there is ample memory available to the build process (see “The Build Environment” in the Gradle User Guide for how to control memory allocation). Smaller projects also benefit from these changes.

No build script or configuration changes, beyond upgrading to Gradle 2.8, are required to leverage these performance improvements.

Faster build script compilation

Build script compilation times have been reduced by up to 30% in this version of Gradle.

This improvement is noticeable when building a project for the first time with a certain version of Gradle, or after making changes to build scripts. This is due to Gradle caching the compiled form of the build scripts.

The reduction in compilation time per script is dependent on the size and complexity of script. Additionally, the reduction for the entire build is dependent on the number of build scripts that need to be compiled.

Faster compilation for continuous builds

In many cases Gradle will spawn a daemon process to host a compiler tool. This is done for performance reasons, as well as to accommodate special heap size settings, classpath configurations, etc. A compiler daemon is started on first use, and stopped at the end of the build.

With Gradle 2.8, compiler daemons are kept running throughout the lifetime of a continuous build session and will only be stopped when the continuous build is cancelled. This improves the performance of continuous builds, since the cost of re-spawning these compilers is avoided for subsequent builds. This change has no impact on non-continuous builds: in this case each compiler daemon will be stopped at the end of the build.

The following compilers are forked and should demonstrate improved performance with continuous builds:

General performance improvements

This release also contains various other performance improvements that are generally applicable to most builds. These improvements are due to the use of more efficient data structures and smarter caching. Build time reductions vary depending on the size and nature of the build.

Convenient injection of classes under test via TestKit API

Previous releases of Gradle required the end user to provide classes under test (e.g. plugin and custom task implementations) to the TestKit by assigning them to the buildscript's classpath.

This release makes it more convenient to inject classes under test through the GradleRunner API with the method withPluginClasspath(Iterable<File>). This classpath is then available to use to locate plugins in a test build via the plugins DSL. The following code example demonstrates the use of the new TestKit API in a test class based on the test framework Spock:

class BuildLogicFunctionalTest extends Specification {
    @Rule final TemporaryFolder testProjectDir = new TemporaryFolder()
    File buildFile
    List<File> pluginClasspath

    def setup() {
        buildFile = testProjectDir.newFile('build.gradle')
        pluginClasspath = getClass().classLoader.findResource("plugin-classpath.txt")
          .readLines()
          .collect { new File(it) }
    }

    def "execute helloWorld task"() {
        given:
        buildFile << """
            plugins {
                id 'com.company.helloworld'
            }
        """

        when:
        def result = GradleRunner.create()
            .withProjectDir(testProjectDir.root)
            .withArguments('helloWorld')
            .withPluginClasspath(pluginClasspath)
            .build()

        then:
        result.standardOutput.contains('Hello world!')
        result.taskPaths(SUCCESS) == [':helloWorld']
    }
}

Future versions of Gradle will aim for automatically injecting the classpath without additional configuration from the end user.

Zip file name encoding

Gradle will use the default character encoding for file names when creating Zip archives. Depending on where the archive will be extracted, this may not be the best possible encoding to use due to the way various operating systems and archive tools interpret file names in the archive. Some tools assume the extracting platform character encoding is the same encoding used to create the archive. A mismatch between encodings will manifest itself as "corrupted" or "mangled" file names.

Zip tasks can now be configured with an explicit character encoding to use for file names and comment fields in the archive. (This option does not affect the content of the files in the archive.) The default behavior has not been changed, so no changes should be necessary for existing builds.

Configuration of the rule priority threshold for PMD incubating feature

By default, the PMD plugin will report all rule violations and fail the build if any violations are found. This means the only way to ignore low priority violations was to create a custom ruleset.

Gradle now supports configuring a "rule priority" threshold. The PMD report will contain only violations higher than or equal to the priority configured, and the build will only fail if one of these "priority" violations is discovered.

You configure the rule priority threshold via the PmdExtension. You can also configure the property on a per-task level through the Pmd task.

pmd {
    rulePriority = 3
}

Better PMD analysis with type resolution incubating feature

Some PMD rules require access to the dependencies of your project to perform type resolution. If the dependencies are available on PMD's auxclasspath, additional problems can be detected.

Gradle now automatically adds the compile dependencies of each analyzed source set to PMD's auxclasspath. No additional configuration should be necessary to enable this in existing builds.

Managed model improvements

A number of improvements have been made to the experimental managed model feature. This feature is currently used by the native and Play plugins and will evolve into a general purpose feature for describing Gradle builds.

Support for Set and List of scalar types

The managed model now supports collections of scalar types. This means that it is possible to use a Set or a List with element type:

  • a JDK Number type (Integer, Double, ...)
  • a Boolean
  • a String
  • a File
  • or an enumeration type

A collection of a scalar type can be attached to any @Managed type as a property, or used for the elements of a ModelSet or ModelMap, or as a top level element. For example:

@Managed
interface User {
    Set<String> getGroups();
}

Collections of scalar types are available as read-only properties, in which case they default to an empty collection, or as read-write properties, in which case they default to null. Read-only properties are similar to final values: they can be mutated as long as they are the subject of a rule. Read-write properties can also be mutated, but they are not final: the collection can be overwritten by a configuration rule.

A read-only (non nullable) property is created by defining only a setter, while a read-write property is created by defining both a setter and a getter:

@Managed
interface User {
    Set<String> getGroups();
    void setGroups(Set<String> groups);
}

Support for FunctionalSourceSet

This release facilitates adding source sets (LanguageSourceSet) to arbitrary locations in the model space through the use of the language-base plugin and FunctionalSourceSet. A FunctionalSourceSet can be attached to any @Managed type as a property, or used for the elements of a ModelSet or ModelMap, or as a top level element.

Using FunctionalSourceSet allows build and plugin authors to strongly model things that use collections of source as LanguageSourceSets. This kind of strongly typed modelling also allows build and plugin authors to access LanguageSourceSets in a controlled and consistent way using rules.

Adding a top level FunctionalSourceSet is a simple as:

model {
    sources(FunctionalSourceSet)
}

or from a RuleSource

class Rules extends RuleSource {
    @Model
    void functionalSources(FunctionalSourceSet sources) {
    }
}
apply plugin: Rules

Here's an example of creating a managed type with FunctionalSourceSet properties.

@Managed
interface BuildType {
    FunctionalSourceSet getSources()
    FunctionalSourceSet getInputs()
    ModelMap<FunctionalSourceSet> getComponentSources()
}

Internal views for components

It is now possible to attach internal information to an unmanaged ComponentSpec. This way a plugin can make some data about its components visible to build logic via a public component type, while hiding the rest of the data behind the internal view type. The default implementation of the component must implement all internal views declared for the component.

interface SampleLibrarySpec extends ComponentSpec {
    String getPublicData()
    void setPublicData(String publicData)
}

interface SampleLibrarySpecInternal extends ComponentSpec {
    String getInternalData()
    void setInternalData(String internalData)
}

class DefaultSampleLibrarySpec extends BaseComponentSpec implements SampleLibrarySpec, SampleLibrarySpecInternal {
    String internalData
    String publicData
}

Components can be targeted by rules via their internal types when those internal types extend ComponentSpec:

class Rules extends RuleSource {
    @Mutate
    void mutateInternal(ModelMap<SampleLibrarySpecInternal> sampleLibs) {
        sampleLibs.each { sampleLib ->
            sampleLib.internalData = "internal"
        }
    }
}

For internal view types that do not not extend ComponentSpec, targeting components can be achieved via ComponentSpecContainer.withType():

@Defaults
void finalize(ModelMap<SampleLibrarySpec> sampleLibs) {
    sampleLibs.withType(SomeInternalView).all { sampleLib ->
        // ...
    }
}

Rule based model configuration

Interoperability between legacy configuration space and new rule based model configuration space has been improved. More specifically, the tasks.withType(..) construct allows legacy configuration tasks to depend on tasks created via the new rule based approach. See this issue for details.

References between model elements

Currently, the managed model works well for defining a tree of objects. This release improves support for a graph of objects, with better support for references between different model elements. In particular, the inputs for a rule can traverse a "reference" property, which is simply a read-write property on a @Managed type that refers to some other model element.

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

The sonar and sonar-runner plugins have been superseded by an external plugin from SonarQube

SonarQube is an open platform to manage code quality, and in previous versions of Gradle the sonar and sonar-runner plugin has provided integration with this analysis tool. An improved plugin is now available directly from the developers of SonarQube. This new plugin supersedes the sonar and sonar-runner plugins that are part of the Gradle distribution; the sonar and sonar-runner plugin are now deprecated and will be removed in Gradle 3.0.

See the official documentation from SonarQube for more details.

Deprecated classes and constants

The following classes have been deprecated and will be removed in Gradle 3.0:

Setting Eclipse project name in beforeMerged or whenMerged hook

Setting the Eclipse project name in eclipse.project.file.beforeMerged or eclipse.project.file.whenMerged hook provided by the Eclipse plugin has been deprecated. Support for this will be removed in Gradle 3.0

Potential breaking changes

Upgraded to Groovy 2.4.4

The Gradle API now uses Groovy 2.4.4. Previously it was using Groovy 2.3.10. This change should be transparent to the majority of users, however it can imply some minor breaking changes. Please refer to the Groovy language changelogs for further details.

New PMD violations due to type resolution changes

PMD can perform additional analysis for some rules (see above), therefore new violations may be found in existing projects. Previously, these rules were unable to detect problems because classes outside of your project were not available during analysis.

Updated to CodeNarc 0.24.1

The default version of CodeNarc has been updated from 0.23 to 0.24.1. Should you want to stay on older version, it is possible to downgrade it using the codenarc configuration:

dependencies {
   codenarc 'org.codenarc:CodeNarc:0.17'
}

Improved IDE project naming deduplication

To ensure unique project names in the IDE, Gradle applies a deduplication logic when generating IDE metadata for Eclipse and Idea projects. This deduplication logic has been improved. All projects with non unique names are now deduplicated. here's an example for clarification:

Given a Gradle multiproject build with the following project structure

root
|-foo
|  \- app
|
\-bar
   \- app

results in the following IDE project name mapping:

root
|-foo
|  \- foo-app
|
\-bar
   \- bar-app

Changes to the incubating integration between the managed model and the Java plugins

The Java plugins make some details about the project source sets visible in the managed model, to allow integration between rules based plugins and the stable Java plugins. This integration has changed in this Gradle release, to move more of the integration into the managed model:

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.