Gradle Release Notes
Version 0.9
- New and Noteworthy
- Migrating from 0.8
- Fixed Jira Issues
New and Noteworthy
Incremental builds
Gradle will now skip a task if its input files have not changed since the task last ran. It will do this for all built-in tasks and for any custom tasks that you write. It can even do this for the ad hoc tasks that you define in your build script. Writing builds which are both large and performant has never been easier.
We've put a lot of effort into making sure that incremental builds are reliable. No more running clean before you run a build. Gradle will take care of things such as cleaning up old classes and resources, and recompiling dependent classes when source files change. This means no more running stale tests or building archives that contain the stale files.
See the user guide for some details about how to use this for your tasks.
Simple build composition using scripts
You can now easily apply any number of build scripts to a project. This allows you to do lots of useful things: you can split a large build script into smaller pieces, you can use it to apply common configuration to multiple projects, or to multiple builds across your organization. You can even implement plugins using scripts.
Scripts can be applied from any URL, which means you can share scripts using HTTP.
You can apply scripts to any arbitrary object, so you can use them to configure any object, such as tasks, repositories or your own custom build objects.
See the user guide
The Gradle Daemon
This release includes the experimental Gradle daemon. The daemon runs in the background, and performs builds. This way it avoids the startup costs.
See the user guide
Gradle build language reference guide
We've added a reference guide for the Gradle build language. This reference guide documents all the properties, methods and script blocks for the main classes that make up the Gradle DSL, along with all of the task implementations.
See http://gradle.org/0.9/docs/dsl/index.html
Gradle Plugin for IDEA
A plugin for IDEA is now available which allows you to explore and run Gradle builds from within IDEA. The plugin is available via the plugin manager in IDEA.
IDE Plugins
We've add an 'idea' plugin which generates the project files for IDEA, and we've rewritten the 'eclipse' plugin. Both plugins automatically discover and download the source and javadoc JARs for all your dependencies. And both plugins offer lots of hooks for flexible configuration.
See the idea plugin and eclipse plugin for details.
New archive task API
The archive tasks now share the same API as the copy task, based on the powerful CopySpec interface. This means that all the capabilities you can use when copying are now available when you create an archive. This includes being able to filter the contents or rename certain files as they are being added to the archive. You can share CopySpecs between tasks, so you can, for example, use the same definition to generate a WAR and an exploded WAR. Or ZIP, TAR and exploded distributions.
In addition, the Jar and War tasks have been much simplified, so that it is much easier to define the contents of the META-INF and WEB-INF directories. The Jar and War tasks are now easily used in builds which don't use the Java or War plugins.
Manifest generation is also much improved. You can share manifest definitions between tasks, import from existing manifest, or merge manifests together in flexible ways.
See working with files and java plugin
Testing
Parallel test execution
The Test task now supports parallel test execution. Enabling this is as easy as setting the maxParallelForks property. So now, you can easily take advantage of those extra cores that weren't doing anything, to speed up your test execution.
Execute a single test
You can run Gradle with \-Dtest.single=SomeClassName to run a single test class.
Maximum tests per process
You can also specify the maximum number of test classes to execute in a forked test process. The process is restarted when the limit is reached. Fork modes 'per test' and 'once' are just special cases of this. This provides an efficient alternative to adding more and more heap space for your test process, without the performance hit of forking per test.
Test listeners
Finally, you can now register a listener to receive notification as tests execute, to do custom reporting or some other test result analysis.
These test features work equally well for JUnit and TestNG test suites.
See the user guide
Antlr support
The new Antlr plugin adds support for generating source from Antlr grammars.
See the user guide
Announce plugin
The new Announce plugin adds support for providing notifications from your build to various destinations, such as twitter, or locally using snarl, libnotify, or growl.
See the user guide
Maven POM generation
You can change or extend what Gradle adds to generated Maven POMs, using exactly the same syntax that polygot Maven uses.
File handling
More useful method have been added to various file handling APIs. For example, you can now obtain the contents of a ZIP file as a file tree, which you can pass to any task which understands file collections (pretty much all of them). The file DSL is now available in all scripts which Gradle executes, not just build scripts.
See the user guide
New tasks
We've added a Sync task, which extends the Copy task to delete any files from the destination directory which were not part of the copy operation. This is useful for things like installing your distribution, or for maintaining a copy of your dependencies in a particular directory.
The general purpose Delete task replaces the specific Clean and EclipseClean tasks.
There's also a new GradleBuild task, which you can use to execute another Gradle build from within your build. We've added an Exec task to execute arbitrary commands, and a JavaExec task to execute arbitrary Java applications.
See the DSL reference
Build profiler
A profiler is now built into Gradle, to help you profile your builds if you have performance problems.
See the user guide
Writing plugins
Added ProjectBuilder to help you test your custom task and plugin implementations.
See the user guide
Updated dependencies
Build scripts are now executed using Groovy 1.7.6 and Ant 1.8.1
- Incremental builds will help your average build time.
- Parallel test execution and reforking can make a huge different for a long running test suite.
- Start-up time has improved thanks to the Gradle daemon and Groovy start-up improvements.
- Large multi-project builds with complex dependency graphs will see significant improvements.
- The test task is highly concurrent internally, so that things like detecting test files, launching processes, and writing results files are all done concurrently.
- Copy and the archive tasks perform streaming to keep memory requirements down.
Migrating from 0.8
Gradle 0.9 Breaking Changes
Fixed Jira Issues
0.9 Breaking Changes
- Build Scripts
- Updated to Groovy 1.7.3
- Using plugins
- Wrapper
- Other Changes
- API Changes
Build Scripts
Updated to Groovy 1.7.3
Build scripts are now executed using Groovy 1.7.3. This should not cause any problems for most build scripts.
Using plugins
The usePlugin() method has been deprecated. Instead, you should use the apply() method.
0.8 | 0.9 |
---|
{code}usePlugin 'java' |
{code}apply plugin: 'java' |
apply plugin: MyPluginClass
// or
apply {
plugin 'java'
plugin MyPluginClass}
Task action closures
The actions passed to
Task.doFirst() and
Task.doLast(), which includes those added using the
<< operator, now delegate to the task first, and then the owner of the closure. Previously, these closure would delegate to the owner first, then the project of the task. These changes make the behaviour of these closures consistent with the behaviour of other closures, such as task configuration closures.
For most cases, existing task action closures will continue to work unmodified. The following properties and methods will now refer to the task, rather than the project:
- name
- path
- convention
- hasProperty()
- property()
- setProperty()
Also, be aware that when you set a dynamic property in the task action closure, it will now set the property on the task, rather than the project.
0.8 |
0.9 |
task show << {
println name
println path
someProp = 'value'
}
|
task show << {
println project.name
println project.path
project.someProp = 'value'
}
|
Task onlyIf()
Each call to
Task.onlyIf() now adds a predicate which must evaluate to true for the task to be executed. Previously, calling this method would replace any previously specified predicate. You can use
Task.setOnlyIf() to get the old behaviour.
Project buildDirName
The
Project.buildDirName property has been deprecated. It has been replaced by the
buildDir property:
0.8 |
0.9 |
buildDirName = 'someDir'
|
buildDir = 'someDir'
|
Tasks
Archive tasks
The Archive tasks now share a common API with the Copy task. This affects the
Zip,
Tar,
Jar and
War tasks.
* The
fileSet() method has been replaced with the
from() method:
0.8 |
0.9 |
zip {
fileSet(dir: 'somedir') {
include '**/*.xml'
}
}
|
zip {
from('somedir') {
include '**/*.xml'
}
}
|
* The
zipFileSet() method has been replaced with the
from() and
into() methods. The equivalent of
prefix,
fileMode and
dirMode are supported. There is no replacement for
fullPath.
0.8 |
0.9 |
zip {
zipFileSet(dir: 'somedir', prefix: 'bin', filemode: '755') {
include '**/*.sh'
}
}
|
zip {
from('somedir') {
into 'bin'
fileMode = 0755
include '**/*.sh'
}
}
// or
zip {
into('bin') {
from 'somedir'
fileMode = 0755
include '**/*.xml'
}
}
|
* The
tarFileSet() method has been replaced by the
from() and
into() methods, as for
zipFileSet(). There are no replacements for
userName,
group,
uid or
gid.
* The
customName property has been merged into the
archiveName property
0.8 |
0.9 |
zip {
customName = 'some.zip'
}
|
zip {
archiveName = 'some.zip'
}
|
* The
resourceCollections() method has been replaced by the
from() method.
0.8 |
0.9 |
zip {
resourceCollections fileTree('somedir')
}
|
zip {
from fileTree('somedir')
}
|
* The
merge() and
mergeGroup() methods have been removed. You can use
Project.zipTree() and
Project.tarTree() to achieve the same thing:
0.8 |
0.9 |
zip {
merge 'some-file.zip'
mergeGroup('some-dir') {
include '*.zip'
}
}
|
zip {
from zipTree('some-file.zip')
fileTree(dir: 'some-dir', includes ['*.zip']).each {
from zipTree(it)
}
}
|
- The antDirective() method has been removed. There is no replacement.
- The createIfEmpty, baseDir, resourceCollections, mergeFileSets and mergeGroupFileSets properties have been removed. There are no replacements.
Jar task
In addition to the changes listed above, the following changes have been made to the
Jar task:
* The
metaInfResourceCollections property has been replaced by the
metaInf() \{...\} method. This operates the same as if a call to
into('META-INF') \{...\} was made:
0.8 |
0.9 |
jar {
metaInfResourceCollections = [fileTree('src/main/META-INF')]
}
|
jar {
metaInf {
from 'src/main/META-INF'
}
}
|
War task
TBD
Copy task
- A destination directory must be provided at the top level of the copy task. Previously, this was optional, provided the destination directory was specified in all nested copy specs.
- The remapTarget method has been removed. You can use the rename method instead.
- The parameter of the into method for a nested copy spec is now evaluated relative to the parent spec's destination directory.
Test task
- The Test task now always executes the tests in a forked process.
- The stopAtErrorsOrFailures property has been replaced by the ignoreFailures property.
JUnit Tests
* The
forkMode property has been replaced by a
forkEvery property.
0.8 |
0.9 |
test {
options.fork.forkMode = ForkMode.PER_TEST
options.fork.forkMode = FrokMode.ONCE
}
|
test {
forkEvery = 1 // or any value > 0
forkEvery = null // this is the default value
}
|
* A number of properties have been moved from
JUnitOptions to
Test
0.8 |
0.9 |
test {
options.systemProperties['someProp'] = 'value'
options.environment['SOME_VAR'] = 'value'
options.fork.jvmArgs = ['-ea', '-Xmx256m']
options.fork.dir = file('someDir')
options.fork.jvm = 'somewhere/bin/java'
options.fork.maxMemory = '1024m'
options.fork.bootstrapClasspath = someClassPath
}
|
test {
systemProperties['someProp'] = 'value'
environment['SOME_VAR'] = 'value'
jvmArgs = ['-ea', '-Xmx256m']
workingDir = file('someDir')
executable = 'somewhere/bin/java'
maxHeapSize = '1024m'
bootstrapClasspath = someClassPath
}
|
- Removed the filterTrace, fork, forkOptions, formatterOptions, outputToFormatters, printSummary, reloading, showOutput and tempDir properties from JUnitOptions.
- Removed the cloneVm, newEnvironment and timeout properties from JUnitForkOptions.
0.8 |
0.9 |
test {
options.cloneVm = true
options.cloneVm = false
options.newEnvironment = false
options.newEnvironment = true
}
|
test {
systemProperties = System.properties
systemProperties = [:] // the default
environment = System.env // the default
environment = [:]
}
|
TestNG Tests
* A number of properties have moved from
TestNGOptions to
Test
0.8 |
0.9 |
test {
useTestNG()
options.systemProperties['someProp'] = 'value'
options.environment['SOME_VAR'] = 'value'
options.jvmArgs = ['-ea', '-Xmx256m']
options.jvm = 'somewhere/bin/java'
options.enableAssert = true
}
|
test {
useTestNG()
systemProperties['someProp'] = 'value'
environment['SOME_VAR'] = 'value'
jvmArgs = ['-ea', '-Xmx256m']
executable = 'somewhere/bin/java'
enableAssertions = true
}
|
* The
skippedProperty,
dumpCommand,
suiteRunnerClass properties have been removed from
TestNGOptions.
Clean task
* The
Clean task has been replaced by the
Delete task.
EclipseClean task
* The
EclipseClean task has been replaced by the
Delete task.
Plugin Authoring
* The
Plugin interface has changed, so that it can target any time of object. The signature of
Plugin.use() has also changed to reflect this:
0.8 |
0.9 |
public class MyPlugin implements Plugin {
void use(Project project, ProjectPluginsContainer projectPluginsHandler) {
// do some stuff to project
}
}
|
public class MyPlugin implements Plugin {
void apply(Project project) {
// do some stuff to project
}
}
|
- A new instance of the plugin is created for each project. Previously, a single instance was created and shared by all projects. This allows you to keep per-project state in the plugin object itself.
- The $GRADLE_HOME/plugin.properties file has been removed. Instead, you can add a resource called META-INF/gradle-plugins/{}_$plugin-id{_}{}.properties to your plugin JAR. This way, you can provide a name for your plugin without requiring the users of your plugin to do anything to their Gradle installation.
0.8 |
0.9 |
$GRADLE_HOME/plugin.properties
myplugin=com.something.MyPluginImpl
|
myplugin.jar!META-INF/gradle-plugins/myplugin.properties
implementation-class=com.something.MyPluginImpl
|
Wrapper
- A Gradle wrapper generated by Gradle 0.8 and earlier will no longer work with Gradle 0.9
Other Changes
- The {-}l{-}, \-K, \-no-imports command-line options have been removed.
- The JDK 1.4 compatible distribution is no longer available.
- The default-imports file is no longer available in the Gradle distribution.
API Changes
- org.gradle.api.TaskAction and org.gradle.api.ProjectAction have been replaced by org.gradle.api.Action.
- Settings and Gradle methods disableStandardOutputCapture(), captureStandardOutput() and getLogger() have been removed. You can use the replacements on org.gradle.api.Script.
- Replaced Project.applyActions() with Project.configure().
- Project.relativePath() now returns a String instead of a File.
- Deprecated constructor DefaultTask(Project, String) has been removed.
- PluginCollection now extends DomainObjectCollection instead of NamedDomainObjectCollection. This means methods such as getByName() are no longer available for a plugin container.
- PluginCollection methods hasPlugin(String), findPlugin(String) and getPlugin(String) only consider those plugins with an id.
- PluginContainer methods usePlugin() have been renamed to apply().
- The project.mkdir(File parent, String name) method provided by the Java plugin has been replaced by project.mkdir(Object paths). The latter resolves relative paths to the project dir.
- GradleException has been moved into the org.gradle.api package and does not have a single-argument constructor taking a Throwable; instead requires a message
- ResolvedDependency.getGroup() has been renamed to ResolvedDependency.getModuleGroup()