The Gradle team is pleased to announce Gradle 4.6.
First and foremost, this release of Gradle includes built-in support for JUnit Platform and the JUnit Jupiter/Vintage Engine, also known as JUnit 5 support. You can use the new filtering and engines functionality in JUnit 5 using the examples provided below and in the documentation.
Thank you to the JUnit team for helping to achieve JUnit Platform support, and a special thank you to Andrew Oberstar for extraordinary contributions toward this effort.
Also regarding testing, you can now improve your testing feedback loop when running JVM-based tests using the new fail-fast option for Test tasks, which stops the build immediately after the first test failure.
// Example JUnit 5 and fail-fast test configuration
test {
useJUnitPlatform {
excludeTags 'slow'
includeEngines 'junit-jupiter', 'junit-vintage'
}
failFast = true
}
Moving on to dependency management improvements: you can now declare dependency constraints for transitive dependencies and avoid problems caused by oft-hidden upstream dependency changes.
This release also features enhanced Maven dependency compatibility: support for importing BOMs, optional dependencies, and compile/runtime separation when consuming POMs. For now you must enable these features by adding enableFeaturePreview('IMPROVED_POM_SUPPORT') to your settings.gradle file, as they break backward compatibility in some cases.
This version of Gradle also comes with a couple especially useful new APIs for task development. You can now declare custom command-line flags for your custom tasks, for example: gradle myCustomTask --myfoo=bar. In addition, tasks that extend Test, JavaExec or Exec can declare rich arguments for invoking the underlying executable. This allows for better modeling of tools like annotation processors.
Speaking of annotation processors, it is now more convenient to declare dependencies that are annotation processors through the new annotationProcessor dependency configuration. Using a separate dependency configuration for annotation processors is a best practice for improving performance.
Kotlin DSL v0.15.6 is included in this release of Gradle, and features initialization scripts support, nicer script compilation error reporting, performance improvements, and better IntelliJ IDEA integration. Details are available in the linked release notes.
We hope you will build happiness with Gradle 4.6, and we look forward to your feedback via Twitter or on GitHub.
play pluginStartParameter.taskOutputCacheEnabledSwitch your build to use Gradle 4.6 quickly by updating your wrapper properties:
gradle wrapper --gradle-version=4.6
Standalone downloads are available at gradle.org/releases.
Here are the new features introduced in this Gradle release.
JUnit 5 is the latest version of the well-known JUnit test framework. JUnit 5 is composed of several modules:
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
The JUnit Platform serves as a foundation for launching testing frameworks on the JVM. JUnit Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5. JUnit Vintage provides a TestEngine for running JUnit 3 and JUnit 4 based tests on the platform.
Gradle now provides native support for JUnit Jupiter/Vintage Engine on top of JUnit Platform. To enable JUnit Platform support, you just need to add one line to your build.gradle:
test {
useJUnitPlatform()
}
Moreover, Tagging and Filtering can be enabled via:
test {
useJUnitPlatform {
// includeTags 'fast'
excludeTags 'slow'
// includeEngines 'junit-jupiter', 'junit-vintage'
// excludeEngines 'custom-engine'
}
}
You can find more information on test grouping and filtering in the Java Plugin documentation.
To enable JUnit Jupiter support, add the following dependencies:
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.0'
}
Put your first Jupiter test into src/test/java/foo/bar:
package foo.bar;
import org.junit.jupiter.api.Test;
public class JUnitJupiterTest {
@Test
public void ok() {
}
}
Now you can run gradle test to see the results of your JUnit 5 tests!
You can find a sample of test with JUnit Jupiter at samples/testing/junitplatform/jupiter in the '-all' distribution of Gradle.
If you want to run JUnit 3/4 tests on JUnit Platform, you should add extra JUnit Vintage Engine dependency:
test {
useJUnitPlatform()
}
dependencies {
testCompileOnly 'junit:junit:4.12'
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.1.0'
}
You can mix JUnit 3/4 tests with Jupiter tests without the need to rewrite old tests. A sample of mixed tests can be found at samples/testing/junitplatform/engine in the '-all' distribution of Gradle.
Note: Use of JUnit 5 features requires Java 8 or higher.
Gradle now supports stopping Test tasks after the first failed test. Projects with large test suites can take a long time to execute even though a failure occurred early on leading to unnecessary wait times (especially on CI). To enable this fail fast behavior in your build file, set the failFast property to true:
test {
failFast = true
}
In addition, this behavior can be enabled from the command line for individual build invocations. An invocation looks like:
gradle integTest --fail-fast
More information is available in the Java Plugin documentation for test execution.
In complex builds, it can become hard to interpret dependency resolution results and why a dependency declaration or a rule was added to a build script. To improve on this situation, we extended all the corresponding APIs with the capability to define a reason for each declaration or rule.
These reasons are shown in dependency insight reports and error messages if the corresponding declaration or rule influenced the resolution result. In the future, they will also be shown in build scans.
dependencies {
implementation('org.ow2.asm:asm:6.0') {
because 'we require a JDK 9 compatible bytecode generator'
}
}
With dependency constraints, Gradle adds a mechanism to express constraints over transitive dependencies which are used during dependency resolution.
dependencies {
implementation 'org.apache.httpcomponents:httpclient'
}
dependencies {
constraints {
implementation('org.apache.httpcomponents:httpclient:4.5.3') {
because 'previous versions have a bug impacting this application'
}
implementation('commons-codec:commons-codec:1.11') {
because 'version 1.9 pulled from httpclient has bugs affecting this application'
}
}
}
In the example, the version of commons-codec that is brought in transitively is 1.9. With the constraint, we express that we need at least 1.11 and Gradle will now pick that version during dependency resolution.
Compared to dependency management rules you can define in the resolution strategy, which are applied after dependency resolution to fix up the result, dependency constraints are declared information that participate in the dependency resolution process. This means that all constraints are considered in combination. For instance, if another dependency brings in an even higher version of commons-codec, Gradle will respect that.
Expressing the same in a traditional dependency substitution rule requires you to repeat part of the dependency resolution process manually – which is expensive and error prone. That is, you would have to inspect the version that was selected and implement a decision based on the version:
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'commons-codec'
&& details.requested.name == 'commons-codec'
&& VersionNumber.parse(details.requested.version) < VersionNumber.parse('1.11')) {
details.useVersion '1.11'
}
}
Note: Dependency constraints are not yet published, but that will be added in a future release. This means that their use currently only targets builds that do not publish artifacts to maven or ivy repositories.
Gradle now provides support for importing bill of materials (BOM) files, which are effectively .pom files that use <dependencyManagement> to control the dependency versions of direct and transitive dependencies. It works by declaring a dependency on a BOM.
dependencies {
// import a BOM
implementation 'org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE'
// define dependencies without versions
implementation 'com.google.code.gson:gson'
implementation 'dom4j:dom4j'
}
Here, for example, the versions of gson and dom4j are provided by the Spring Boot BOM.
Note: This is a Gradle 5.0 feature preview, which means it is a potentially breaking change that will be activated by default in Gradle 5.0. It can be turned on in Gradle 4.6+ by adding enableFeaturePreview('IMPROVED_POM_SUPPORT') in settings.gradle.
Gradle now creates a dependency constraint for each dependency declaration in a POM file with <optional>true</optional>. This constraint will produce the expected result for an optional dependency: if the dependency module is brought in by another, non-optional dependency declaration, then the constraint will apply when choosing the version for that dependency (e.g., if the optional dependency defines a higher version, that one is chosen).
Note: This is a Gradle 5.0 feature preview, which means it is a potentially breaking change that will be activated by default in Gradle 5.0. It can be turned on in Gradle 4.6+ by adding enableFeaturePreview('IMPROVED_POM_SUPPORT') in settings.gradle.
Since Gradle 1.0, runtime scoped dependencies have been included in the Java compile classpath, which has some drawbacks:
runtime files that do not impact compilation, resulting in unnecessary re-compilation when these files change.Now, if this new behavior is turned on, the Java and Java Library plugins both honor the separation of compile and runtime scopes. Meaning that the compile classpath only includes compile scoped dependencies, while the runtime classpath adds the runtime scoped dependencies as well. This is in particular useful if you develop and publish Java libraries with Gradle where the api/implementation dependencies separation is reflected in the published scopes.
Note: This is a Gradle 5.0 feature preview, which means it is a potentially breaking change that will be activated by default in Gradle 5.0. It can be turned on in Gradle 4.6+ by adding enableFeaturePreview('IMPROVED_POM_SUPPORT') in settings.gradle.
Gradle now allows you to explicitly state for which metadata files it should search in a repository. Use the following to configure Gradle to fail-fast resolving a dependency if a POM file is not found first.
repositories {
mavenCentral {
metadataSources {
mavenPom() // Look for Maven '.pom' files
// artifact() - Do not look for artifacts without metadata file
}
}
}
This avoids a 2nd request for the JAR file when the POM is missing, making dependency resolution from Maven repositories faster in this case.
It is now even easier to add annotation processors to your Java projects. Simply add them to the annotationProcessor configuration:
dependencies {
annotationProcessor 'com.google.dagger:dagger-compiler:2.8'
implementation 'com.google.dagger:dagger:2.8'
}
Declaring annotation processors on a separate configuration improves performance by preserving incremental compilation for tasks that don't require annotation processors.
Sometimes a user wants to declare the value of an exposed task property on the command line instead of the build script. Being able to pass in property values on the command line is particularly helpful if they change more frequently. With this version of Gradle, the task API now supports a mechanism for marking a property to automatically generate a corresponding command line parameter with a specific name at runtime. All you need to do is to annotate a setter method of a property with Option.
The following examples exposes a command line parameter --url for the custom task type UrlVerify. Let's assume you wanted to pass a URL to a task of this type named verifyUrl. The invocation looks as such: gradle verifyUrl --url=https://gradle.org/. You can find more information about this feature in the documentation on declaring command-line options.
import org.gradle.api.tasks.options.Option;
public class UrlVerify extends DefaultTask {
private String url;
@Option(option = "url", description = "Configures the URL to be verified.")
public void setUrl(String url) {
this.url = url;
}
@Input
public String getUrl() {
return url;
}
@TaskAction
public void verify() {
getLogger().quiet("Verifying URL '{}'", url);
// verify URL by making a HTTP call
}
}
Gradle 4.5 added the possibility to add CommandLineArgumentProviders to CompileOptions, thus enabling plugin authors to better model tools like annotation processors.
Now we introduce CommandLineArgumentProviders to Exec, JavaExec and Test, both to model command line arguments (Exec and JavaExec) as well as JVM options (JavaExec and Test).
For example, the built-in jacoco plugin uses this new feature to declare the inputs and outputs of the JaCoCo agent added to the test task.
class JacocoAgent implements CommandLineArgumentProvider {
private final JacocoTaskExtension jacoco;
public JacocoAgent(JacocoTaskExtension jacoco) {
this.jacoco = jacoco;
}
@Nested
@Optional
public JacocoTaskExtension getJacoco() {
return jacoco.isEnabled() ? jacoco : null;
}
@Override
public Iterable<String> asArguments() {
return jacoco.isEnabled() ? ImmutableList.of(jacoco.getAsJvmArg()) : Collections.<String>emptyList();
}
}
task.getJvmArgumentProviders().add(new JacocoAgent(extension));
For this to work,