Gradle 1.6 sees some fantastic new features contributed by the Gradle community: Task ordering rules offer you more control over the execution of tasks, there's now a JaCoCo plugin for test coverage, and the Junit integration supports test categories.
To help get you started with Gradle, this release introduces the build setup plugin. This plugin takes care of the work of setting up a new build. This includes support for converting an Apache Maven POM to a Gradle build. You simply point Gradle at your current Maven build and you end up with a functioning Gradle build. Note that this plugin is in early stages of development and we plan to improve it in future releases.
Continuing on the performance work of the last few releases, Gradle 1.6 includes support for incremental tasks. These are tasks that selectively process only those inputs that have changed, and avoid processing those inputs that have not changed.
The Gradle team also invites you to the first ever “Gradle Summit” (Sponsored by Gradleware), held June 13th - 14th in Santa Clara, California. The summit will be two fully packed days of technical sessions given by Gradle core developers ranging from introductory to deep dive as well as informational sessions by several large organizations on how they get the most out of Gradle. In between sessions there'll be plenty of opportunity for talking to other Gradle users and the Gradle development team. This is an event not to miss. Registration is now open.
Read on for more details on why you should upgrade to Gradle 1.6. As always, please share your feedback and experiences with Gradle 1.6 via the Gradle Forums.
add()
method on incubating PublicationContainer
ProjectDependency
and ExtensionContainer
now have an internal protocolStartParameter.isParallelThreadCountConfigured()
method removedModelBuilder
ProjectConnection.model()
no longer throws UnknownModelException
GRADLE_WRAPPER_ALWAYS_UNPACK
and GRADLE_WRAPPER_ALWAYS_DOWNLOAD
no longer supportedHere are the new features introduced in this Gradle release.
In the past, the only way to ensure that Gradle ran one task after another was to add a dependency between those tasks. So if Task A
must always run before Task B
, you would say that B.dependsOn(A)
. This has the added effect of forcing Task A
to always run if Task B
is executed.
In some cases, dependsOn
is not the correct semantics. A simple example is “clean” must always run before “build”, but you don't always want to run “clean” whenever you run “build”. For this use case Gradle now has “task ordering” rules, the first of which is Task.mustRunAfter
. This rule does not change which tasks will be executed, but it does influence the order in which they will be executed.
task clean { ... }
task build { ... }
build.mustRunAfter clean
In this example you can still execute gradle clean
and gradle build
independently, but running gradle build clean
will cause 'clean' to be executed before 'build'.
Another example is a test-aggregation task that consumes the outputs of all of the test tasks. You want this aggregation task to run after all test tasks, but you do not necessarily want to force all test tasks to run.
task runUnitTests(type: Test) { ... }
task runIntegTests(type: Test) { ... }
task createTestReports { ... }
createTestReports.mustRunAfter tasks.withType(Test)
task allTest(dependsOn: [runUnitTests, runIntegTests, createTestReports]) // This will run unit+integ tests and create the aggregated report
task unitTest(dependsOn: [runUnitTests, createTestReports]) // This will run unit tests only and create the report
task integTest(dependsOn: [runIntegTests, createTestReports]) // This will run integ tests only and create the report
Note that it would not be suitable to use createTestReport.dependsOn(runUnitTests)
in this case, since that would make it difficult to execute the integration tests and generate the report, without running the unit tests. The mustRunAfter
task ordering rule makes it easy to wire this logic into your build.
See the User guide section on “Ordering Tasks” for more information.
On behalf of the Gradle community, the Gradle development team would like to thank Marcin Erdmann for taking on this long anticipated feature. The design and implementation of task ordering rules involved a deep understanding and refactoring of the Gradle Task execution engine, and Marcin took this on with gusto.
Gradle now ships with a JaCoCo plugin to generate code coverage reports. JaCoCo is a free code coverage library for Java.
To gather code coverage information for your java project, just apply the JaCoCo plugin:
apply plugin: 'jacoco'
and run gradle test jacocoTestReport
which generates code coverage reports for the test
task introduced by the java
plugin. The JacocoReport
adds a mustRunAfter
dependency on the coverage data producing task (test
in our example). After the build has finished you find the coverage report in build/reports/jacoco/test
.
You can configure every task of type JacocoReport
to enable other output formats than the default HTML
report. For example, if you just want the XML
coverage report that can be reused by your favourite CI server, you can simply configure this:
jacocoTestReport {
reports {
html.enabled = false
csv.enabled = false
xml.enabled = true
}
}
In some scenarios it might be desirable to compute code coverage not by running tests, but by running the application itself. Since the JaCoCo plugin can be used in combination with any JavaExec
task of your build, it's quite simple to combine the JaCoCo
plugin with the run
task introduced by the application
plugin:
jacoco {
applyTo run
}
task applicationCodeCoverageReport(type: JacocoReport) {
executionData run
sourceSets sourceSets.main
}
This plugin was contributed by Andrew Oberstar, an energetic member of the Gradle community, and is a long requested out-of-the-box feature that is a very welcome addition.
Gradle 1.6 introduces a build-setup
plugin that makes initializing new Gradle builds more convenient. It also supports the migration of an Apache Maven build to a Gradle build by generating a build.gradle
file from a pom.xml
.
The build-setup
plugin is not a plugin that you would apply to your project. Instead, you use it by executing the setupBuild
task in a directory that does not contain any Gradle build files. This will do the following:
pom.xml
exists, a build.gradle
and settings.gradle
file is generated based on its content (e.g. equivalent dependency definitions).pom.xml
exists, a basic build.gradle
and settings.gradle
file is generated.For more information please see the User Guide chapter on this plugin.
This plugin is an incubating feature and will improve and expand in scope in future releases. If you're interested in its progress and future, you can check out the design spec.
@Category
incubating featureThanks to a contribution by Uladzimir Mihura, Gradle now supports JUnit categories. Categories are a mechanism to label and group JUnit tests by using annotations.
Given the following JUnit test code:
public interface FastTests { /* category marker interface */ }
public interface SlowTests { /* category marker interface */ }
public class MyTestClass {
@Category(SlowTests.class)
@Test public void testA() {
…
}
@Category(FastTests.class)
@Test public void testB() {
…
}
}
You can now easily configure your test task to run only specific categories:
test { // run fast unit test only
useJUnit {
includeCategories 'org.gradle.categories.FastTests'
excludeCategories 'org.gradle.categories.SlowTests'
}
}
The includeCategories
and excludeCategories
are methods of the JUnitOptions object and take the full class names of one or more category annotations to include or exclude.
One of Gradle's most prized features is its ability to build a project incrementally. If tasks declare their inputs and outputs, Gradle can optimize the build by skipping the execution of each task whose inputs and outputs are unchanged since the previous execution (because the work would be completely redundant). This is known as “Incremental Build”. Gradle 1.6 introduces a related, incubating, feature that takes build optimization to the next level: “Incremental Tasks”.
An “incremental task” is able to selectively process inputs that have changed, avoiding processing inputs that have not changed and do not need reprocessing. Gradle provides information about changes to inputs to the task implementation for this purpose.
To implement an incremental task, you add a @TaskAction
method that takes a single parameter of type IncrementalTaskInputs. You can then supply an action to execute for every input file that is out of date, and another action to execute for every input file that has been removed.
@TaskAction
void execute(IncrementalTaskInputs inputs) {
inputs.outOfDate { change ->
println "File ${change.file.name} is out of date"
}
inputs.removed { change ->
println "File ${change.file.name} has been removed"
}
}
Note: Incremental task support is a complicated and challenging feature to support. Since the introduction of the implementation described above (early in the Gradle 1.6 release cycle), discussions within the Gradle community have produced superior ideas for exposing the information about changes to task implementors. As such, the API for this feature will almost certainly change in upcoming releases. However, please do experiment with the current implementation and share your experiences with the Gradle community. The feature incubation process (which is part of the Gradle feature lifecyle) exists for this purpose of ensuring high quality final implementation through incorporation of early user feedback.
Be sure to check out the User Guide chapter and DSL reference for more details on implementing incremental tasks.
In previous versions of Gradle it was possible for a Gradle distribution installed implicitly via the Gradle Wrapper to be corrupted, or to fail to install, if more than one process was trying to do this at the same time. This was more likely to occur on a continuous build server than a developer workstation. This no longer occurs as the installation performed by the wrapper is now multi process safe.
Important: leveraging the new multi process safe wrapper requires updating the gradle-wrapper.jar
that is checked in to your project. This requires an extra step to the usual wrapper upgrade process.
First, update your wrapper as per usual by updating the gradleVersion
property of the wrapper task in the build…
task wrapper(type: Wrapper) {
gradleVersion = "1.6"
}
Then run ./gradlew wrapper
to update the wrapper definition. This will configure the wrapper to use and download Gradle 1.6 for future builds, but it has not updated the gradle-wrapper.jar
that is checked in to your project. To do this, simply run ./gradlew wrapper
again. This is necessary as the wrapper jar is sourced from the Gradle environment that is running the build.
If you are seeding a new project using an installation of Gradle 1.6 or higher, you do not need to run the wrapper task twice. It is only necessary when upgrading the wrapper from an older version.
The Gradle
type, which is configured by init scripts, and the Settings
type, which is configured by settings scripts, now accept plugins. Previously, you could apply scripts to these types, but not binary plugins.
This change means that you can now package up init or settings logic in a binary plugin and apply this plugin from the appropriate script, in exactly the same way you do for projects. And this means that you can reuse and share these plugins in exactly the same way.
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 2.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.
groovy
configuration is deprecatedSince Gradle 1.4, the preferred way to specify the Groovy library is to add it to the compile
(or testCompile
) configuration, rather than the groovy
configuration. Therefore, the groovy
configuration is now deprecated. Simply replace groovy
with compile
in the dependencies
block:
dependencies {
compile "org.codehaus.groovy:groovy-all:2.0.6"
}
In some cases (for example if a renamed Groovy Jar is used), it may be necessary to additionally configure the groovyClasspath
of GroovyCompile
and Groovydoc
tasks.
For additional background information about this change, see the Groovy chapter of the Gradle user guide.
scalaTools
configuration is deprecatedSince Gradle 1.4, the Scala compiler to be used is inferred from the scala-library
dependency added to the compile
(or testCompile
) configuration. Therefore, the scalaTools
configuration is now deprecated. Simply remove any scalaTools
dependency declaration and just declare a scala-library
compile (or testCompile
) dependency:
dependencies {
compile "org.scala-lang:scala-library:2.10.1"
}
In some cases (for example if the inferred scala-compiler
dependency isn't available from any of the declared repositories), it may be necessary to additionally configure the scalaClasspath
of ScalaCompile
and ScalaDoc
tasks.
For additional background information about this change, see the Scala chapter of the Gradle user guide.
add()
methodsTo improve consistency in the Gradle API, we've replaced the container add()
methods with a create()
method. Since well before Gradle 1.0, every container type has had a number of create()
methods which both create a new object and add it to the container. Some older container types also define an add()
method which does the same thing, but also conflicts with the add()
method inherited from java.util.Collection
which simply adds an object rather than creating it. To simplify this, these add()
methods have now been deprecated and will be removed in Gradle 2.0.
The methods in question are:
ConfigurationContainer.add()
SourceSetContainer.add()
TaskContainer.add()
StartParameter.getMergedSystemProperties()
method is deprecatedThis method was used internally and was not intended to form part of the public API. It has now been deprecated and will be removed in Gradle 2.0.
add()
method on incubating PublicationContainer
The incubating org.gradle.api.publish.PublicationContainer introduced by the new publish plugins leverages the new support for polymorphic domain object containers in Gradle. This change involved switching from the custom add
() methods to the standard create()
, as described above. The semantics of the replacement methods is identical to those replaced.
This change does not effect publications added to the PublicationContainer using a configuration block, but will impact publications added directly using the add()
method.
ProjectDependency
and ExtensionContainer
now have an internal protocolThis means that the users should not create their own implementations of org.gradle.api.artifacts.ProjectDependency
or org.gradle.api.plugins.ExtensionContainer
. This change should not affect any builds because there are no known use cases supporting custom instances of these API classes.
The exception thrown by Gradle when on build script error or other configuration problem has changed. All such exceptions are now chained in a ProjectConfigurationException
. This change will only impact code that explicitly catches and processes an exception thrown by Gradle when configuring a project.
StartParameter.isParallelThreadCountConfigured()
method removedThis incubating method was used internally and was not intended to form part of the public API. It has now been removed.
ModelBuilder
In Gradle 1.6, we've started work to allow plugins to provide custom tooling API models. A consequence of this work is that the tooling API models are no longer required to extend the org.gradle.tooling.model.Model
marker interface. The upper bound extends Model
has been removed from the type parameter of ModelBuilder
. This change should be both source and binary compatible.
ProjectConnection.model()
no longer throws UnknownModelException
To support for custom tooling API models, it is no longer possible to determine whether a model is supported without configuring the target build. This exception is now thrown when the result is requested, rather than when the builder is created.
GRADLE_WRAPPER_ALWAYS_UNPACK
and GRADLE_WRAPPER_ALWAYS_DOWNLOAD
no longer supportedThe Gradle wrapper no longer supports the GRADLE_WRAPPER_ALWAYS_UNPACK
and GRADLE_WRAPPER_ALWAYS_DOWNLOAD
environment variables. Instead, the wrapper is now much better at recovering from failures to download or unpack the distribution.
The set of default imports is now generated directly from the Gradle API. This means that the default imports now includes a number of additional packages that were not previously imported by default. These packages may contain classes that conflict with other imports present in your build scripts.
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 are problems that were discovered post release that are directly related to changes made in this release.