We can exclude transitive dependencies easily from specific configurations. To exclude them from all configurations we can use Groovy's spread-dot operator and invoke the exclude() method on each configuration. We can only define the group, module or both as arguments for the exclude() method.
The default behavior of Gradle to pick the newest version also applies if a lower version has been declared locally, but another dependency transitively pulls in a newer version. This is in contrast with Maven, where a locally declared version will always win.
For example, if your build.gradle specifies the dependency org.springframework:spring-tx:3.2.3.RELEASE, and another dependency declares 4.0.5.RELEASE as a transitive dependency, then 4.0.5.RELEASE will take precedence:
dependencies {
compile("org.springframework.data:spring-data-hadoop:2.0.0.RELEASE")
compile("org.springframework:spring-tx:3.2.3.RELEASE")
// will select org.springframework:spring-tx:4.0.5.RELEASE
}
The other option is to use force on the dependency itself:
dependencies {
compile("org.springframework.data:spring-data-hadoop:2.0.0.RELEASE")
compile("org.springframework:spring-tx:3.2.3.RELEASE") {
force = true
}
}
This is perhaps the option that is most similar to Maven.
Note that if both ResolutionStrategy.force and ExternalDependency.force are used, the former takes precedence over the latter.
https://github.com/gradle/gradle/issues/3317
org.gradle.tooling.GradleConnectionException: Could not create an instance of Tooling API implementation using the specified Gradle distribution 'https://services.gradle.org/distributions/gradle-4.2-bin.zip'.
Caused by: java.lang.IllegalArgumentException: Could not determine java version from '9.0.1'.
the project needs to use Gradle 4.2.1 or above. Alternatively you can start Eclipse with Java 8.
Finally, Gradle provides an interactive web-based UI for debugging and optimizing builds: build scans. These can also be hosted on-premise to allow an organization to collect build history and do trend analysis, compare builds for debugging, or optimize build times.
Gradle is a build automation system that is fully open source and uses the concepts you see on Apache Maven and Apache Ant. It uses domain-specific language based on the programming language Groovy, differentiating it from Apache Maven, which uses XML for its project configuration. It also determines the order of tasks run by using a directed acyclic graph.
Several developers created Gradle and first released in 2007, and in 2013, it was adopted by Google as the build system for Android projects. It was designed to support multi-project builds that are expected to be quite huge. It also allows for incrementally adding to your build, because it knows which parts of your project are updated. Tasks that are dependent on updated parts are no longer re-executed.
Before starting, make sure you have the following plugins installed:
Gradle Plugin for Eclipse.
Groovy Plugin for Eclipse.
before adding breakpoints you need to tell Eclipse this is a Groovy project: just choose the Configure|Convert to Groovy Project from the project contextual menu (I did this in the Navigator view, selecting the project itself and right-clicking the mouse).
Maven offers a nice script to allow for attaching a debugger to your build, mvnDebug. Gradle does not. Again, though, Gradle makes it pretty easy to add this to your build.
test {
if (System.getProperty('DEBUG', 'false') == 'true') {
jvmArgs '-Xdebug',
'-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009'
}
}
From the command line, issue gradle -DDEBUG=true test:
run {
if (System.getProperty('DEBUG', 'false') == 'true') {
jvmArgs '-Xdebug',
'-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009'
}
}
To add this all of your projects, you can make this change to init.gradle:
dependencies {
api 'commons-httpclient:commons-httpclient:3.1'
implementation 'org.apache.commons:commons-lang3:3.5'}
Dependencies appearing in the api configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers.
Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers' compile classpath. This comes with several benefits:
dependencies do not leak into the compile classpath of consumers anymore, so you will never accidentally depend on a transitive dependency
faster compilation thanks to reduced classpath size
less recompilations when implementation dependencies change: consumers would not need to be recompiled
cleaner publishing: when used in conjunction with the new maven-publish plugin, Java libraries produce POM files that distinguish exactly between what is required to compile against the library and what is required to use the library at runtime (in other words, don't mix what is needed to compile the library itself and what is needed to compile against the library).
The compile configuration still exists but should not be used as it will not offer the guarantees that the api and implementation configurations provide.
tl;dr
Just replace:
compile with implementation
testCompile with testImplementation
debugCompile with debugImplementation
androidTestCompile with androidTestImplementation
compileOnly is still valid. It was added in 3.0 to replace provided and not compile. (providedintroduced when Gradle didn't have a configuration name for that use-case and named it after Maven's provided scope.)
If you are using recent version of Gradle, you can use --refresh-dependencies option.
./gradlew build --refresh-dependencies
you can refer the gradle manual.
The --refresh-dependencies option tells Gradle to ignore all cached entries for resolved modules and artifacts. A fresh resolve will be performed against all configured repositories, with dynamic versions recalculated, modules refreshed, and artifacts downloaded.
Generally, you can refresh dependencies in your cache with the command line option --refresh-dependencies. You can also delete the cached files under ~/.gradle/caches. With the next build Gradle would attempt to download them again.
I was getting exactly same error and I changed the version of gradle that I was using. Inside my gradle-wrapper.properties, changed version 2.4 to 2.2.1 and error is gone.
Initialization - In this phase the gradle build is initialized. Gradle scans the project and its sub projects to create a Project instance of each project and sub project.
Configuration - In this phase the gradle build is configured. In this phase a Task tree is created which determines how and when to run the tasks.
Execution - In this phase the gradle build is executed. This phase actually runs the tasks configured in the configuration phase.
In order to achieve separation of concerns we can separate the different types of tests (e.g. unit, integration, acceptance), allowing us to prioritise unit tests and other verification tasks before integration tests in our task execution graph, thus reducing time spent waiting on all of the tests to fail before determining that one early and quick-to-execute unit test had failed early on in the process. Failing fast is an important concept of the Agile software development methodology as it allows the learning process to begin as early as possible, providing the shortest feedback loop available for the developer to begin fixing a failing test.
a SourceSet represents a set of Java source files and miscellaneous resources, the directories for which we need to configure relative to the working directory of the sub-project.
The following code creates a new SourceSet named integTest and configures the directory paths for both its Java source files and resource files:
Provides, at compile-time, the classes produced by the main and testSourceSets, allowing the integration tests to access the production code in main and allowing them to reuse any unit test helper methods in test.
Provides, at compile-time, the dependencies that both main and testrequire in order to successfully compile.
Provides, at run-time, the dependencies that both main and testrequire to run.
When set to true, Gradle will run the build with remote debugging enabled, listening on port 5005. Note that this is the equivalent of adding -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005to the JVM command line and will suspend the virtual machine until a debugger is attached. Default is false.
When set to quiet, warn, lifecycle, info, or debug, Gradle will use this log level. The values are not case sensitive. The lifecycle level is the default. See the section called “Choosing a log level”
Debugging
The test task provides a Test.getDebug() property that can be set to launch to make the JVM wait for a debugger to attach to port 5005 before proceeding with test execution.
This can also be enabled at invocation time via the --debug-jvm task option (since Gradle 1.12).
— profile will tell gradle to measure the time taken to execute each task and dump that data into HTML file. You can find that report under /projectDir/build/reports/profile directory.
Gradle has three distinct phases in build life cycle:
Initialisation: In this stage of the build life cycle, gradle picks the project and decides what things to build.
Configuration: Here, gradle will evaluate your build.gradle script, configure all the plugins and evaluate the task graph.
Execution: In this phase gradle actually runs all the task those were evaluated in previous phase to get the work done and build the application.
As you can see that out of all three phases, only execution phase performs all the operations.
That means that first two phases are just overhead to the gradle build process. We don’t care about them. But, sadly whenever you do anything with gradle this two phases will always get executed.
So, how can we measure the time taken to execute first two phases? Luckily, gradle provides — dry-run command, that tells gradle to evaluate the project but don’t run any task. Thus execution phase won’t get executed. So, run this command in your terminal:
You can see in above statistics that gradle passed almost 7.8 seconds just to initialise and configure the project. That is completely waste of time for us.
Gradle provides — configure-on-demand flag, that will tell gradle to only build the projects that it really needs to build. Let’s run this command.
So, always make sure that you are using the latest version of the gradle. You can go to /gradle/wrapper/gradle-wrapper.properties and upgrade gradle version by changing distributionUrl.
gradle assemble
To list all available tasks for your project, try:
gradle tasks
Avoid heavy computations, like increasing the version code from git commits count or downloading some files from url while building the project. Gradle will spend time to perform those computations or network operations and that will afftect build timings.
Don’t use dynamic dependency like,
compile 'com.android.support:appcompat-v7:23.0.+'
If you are using the dynamic dependencies, gradle will go online and check if there is any newer version for the library is available or not? (Most of the time, it is just waste of the precious build time). Instead, use the fixed dependencies and update them manually time to time.
compile 'com.android.support:appcompat-v7:23.0.2'
org.gradle.daemon=true
# Try and findout the best heap size for your project build.
org.gradle.jvmargs=-Xmx3096m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# Modularise your project and enable parallel build
org.gradle.parallel=true
# Enable configure on demand.
org.gradle.configureondemand=true
there is now no reason to use mavenCentral() over jcenter() in your repositories blocks. JCenter is bigger, more secure and - even if ever so slightly - faster.
Project names can only be changed in settings.gradle. For example:
include "foo" // or `includeFlat`, doesn't matter
// always good to nail down the root project name, because
// the root directory name may be different in some envs (e.g. CI)
// hence the following even makes sense for single-project builds
rootProject.name = "bar"
// change subproject name
project(":foo").name = "foofoo"
Alternatively, you can use the desired project name in the include statement, and later reconfigure the project directory:
include "foofoo"
project(":foofoo").projectDir = file("foo")
To give some background, the only difference between include and includeFlat is that they use different defaults for the project's projectDir. Otherwise they are the same.
The plugins block is the newer method of applying plugins, and they must be available in the Gradle plugin repository. The apply approach is the older, yet more flexible method of adding a plugin to your build.
The new plugins method does not work in multi-project configurations (subprojects, allprojects), but will work on the build configuration for each child project.
I would think that as functionality progresses, the plugins configuration method will overtake the older approach, but at this point both can be and are used concurrently.
Start up script
All the files with .gradle extension under <USER_HOME>/.gradle/init.d directory are treated as initialization scripts.
init.gradle under <USER_HOME>/.gradle/ are treated as an initialization script
All the files with the .gradle extension under <GRADLE_HOME>/init.d/ directory.
You can even specify any Gradle file as the initialization script with -I <file name> or --init-script <file name>.
Along with project-level properties, you can also define system-level properties in the gradle.properties file. To define system-level properties, you can append properties with systemProp. So systemProp.sProp1=sVal1 will set sProp1 as a system-level property with the value sVal1.
You can define runtime properties on the command line also using the -P and -D options. Using -P, you can define project-specific properties. Using -D, you can define system-level properties. To access system-level properties, you can use System.properties['<propertyname>']. https://medium.com/@wasyl/make-your-gradle-builds-fast-again-ea323ce6a435
I originally was using one RUN command per shell line that I wanted to exectue:
Example:
RUN service postgresql start
RUN su postgres -c "createuser -d -r -s root"
The Problem
I wanted to separate the commands in order to optimize recreation of other images. But I'd always get the error that postgres wasn't running. That's exactly because each RUN command is a separate layer of running machine. Starting postgres in a RUN command does nothing because as soon as the next RUN command is reached, I'm in a new VM, and there's no postgres running at all.
The Solution
Join commands that are part of one cohesive set up step into one RUN statement:
(Note, thanks @outrunthewolf for pointing out that line continuations \ can be used to carry the same command across multiple lines for readability).
RUN service postgresql start && \
su postgres -c "createuser -d -r -s root"
Online guides for installing and setting up postgres instruct the user to run commands as sudo, but this won't work with a Dockerfile because the commands are running as root, and root doesn't have access to the sudo command.
The Solution
Use su {USER}-c "commands go here" instead to execute commands as a different user.
FROM ubuntu
MAINTAINER MurphyRandle, murphy@spacemonkey.com
# Install Postgresql deps
RUN apt-get install -y postgresql postgresql-contrib
# Postgresql setup:
RUN service postgresql start && su postgres -c "createuser -d -r -s root"&& createdb accounts && service postgresql stop
ENTRYPOINT ["/bin/bash"]
Could not create an instance of type org.gradle.invocation.DefaultGradle_Decorated
- check the ownership whether /.gradle is created correctly.
build.gradle that defines the build configuration scripts
gradle.properties
settings.gradle
The settings.gradle file is, just like the build.gradle file, a Groovy script. Only one settings.gradle script will be executed in each build (in comparison to the build.gradle script in multi-project builds). It will be executed before any build.gradle and even before the Project instances are created. Therefore, it is evaluated against a Settings object. With this Settings object, you can add subprojects to your build, modify the parameters from the command line (StartParameter) and access the Gradle object to register lifecycle handlers. Use the file, if your settings are build-related and not necessarily project-related or require logic before possible subprojects are included.
The gradle.properties file is a simple Java Properties file, that only gains it special role by being automatically included into the scope of the Project object (as so-called project properties). It's a simple key-value store, that only allows string values (so you need to split lists or arrays by yourself). You can put gradle.properties files to these locations:
directly in the project directory (for project-related values)
in the user home .gradle directory (for user- or environment-related values)
https://www.packtpub.com/mapt/book/web_development/9781783982363/5/ch05lvl1sec29/the-settings.gradle-file During initialization, Gradle reads the settings.gradle file to figure out which projects are to take part in a build. Gradle creates an object of type Setting. This happens even before any build.gradle is parsed. It is usually placed in the root project parallel to build.gradle. It is recommended to put setting.gradle in the root project, otherwise we have to explicitly tell Gradle the location to the settings file with the command-line option -c.
The most common use of settings.gradle is to enlist all the subprojects participating in the build:
task stopTomcat(type:Exec) {
workingDir '../tomcat/bin'//on windows:
commandLine 'cmd', '/c', 'stop.bat'//on linux
commandLine './stop.sh'//store the output instead of printing to the console:
standardOutput = new ByteArrayOutputStream()
//extension method stopTomcat.output() can be used to obtain the output:
ext.output = {
return standardOutput.toString()
}
}
One way to solve that is to move the call of the copy method into a doLast block:
task copyJarToBin {
doLast {
copy {
from 'build/libs/GradleJarProject.jar'
into "d:/tmp"}}}
The problem with this approach is that you won't benefit of gradles incremental build feature and copy that file every single time you execute the task even though the file hasn't changed.
A better and more idionmatic way of writing your copyJarToBin task is to change your task implementation to use the Copy task type:
task copyJarToBin(type:Copy){
from 'build/libs/GradleJarProject.jar'
into "d:/tmp"}
We can even improve this snippet by taking advantage of gradle's autowiring feature. You can declare the output of one task as input to another. So instead of writing `build/libs/GradleJarProject.jar' you can simply do:
task copyJarToBin(type:Copy){
from createJar // shortcut for createJar.outputs.files
into "d:/tmp"}
Now you don't need to bother about task ordering as gradle know that the createJar task must be executed before the copyJarToBin task can be executed.
<< is equivalent for clean.doLast. doFirst and doLast are ordering the operations at the execution phase, which is seldom relevant for delete operations.
In this case you don't need any of them. The clean task from base is of type Delete, so you simply need to pass it a closure to tell it at configuration time what to delete when it executes:
clean {
delete 'someFile'
}
AS mushfek0001 correctly points it out in his answer, you should use double quotes for variable interpolation to work:
clean {
delete "${buildDir}/someFile"
}
You need to have at least the base plugin applied for this to work, most other plugins, like the Java plugin either apply base or declare their own clean task of type delete Delete task. The error you would get if you don't have this is a missing clean method one.
//select specific test method
gradle test --tests org.gradle.SomeTest.someFeature
//select specific test class
gradle test --tests org.gradle.SomeTest
//select all tests from package
gradle test --tests org.gradle.internal*
//select all ui test methods from integration tests by naming convention
gradle test --tests *IntegTest*ui*
//selecting tests from different test tasks
gradle test --tests *UiTest integTest --tests *WebTest*ui
The thing is that Gradle has to configure all tasks specified in build script beforeactual build is started. It doesn't matter if certain task will be executed - it still needs to be configured.
And the answer is - the part specified within the top-level of the task - is task configuration section. I.e:
task myTask {
def name = "Pavel" //<-- this is evaluated during configuration
println "Hello, World!"////<-- this is also evaluated during configuration
}
That's why when I call gradle tasks I can see "Hello, World!" - this is our configuration section is executed. But that's not really what I want - I want "Hello, World!" to be printed only when I explicitly call my task.
task myTask {
def text = 'Hello, World!' //configure my task
doLast {
println text //this is executed when my task is called
}
}
def myClosure = {String str, int num -> println "$str : $num" }
Another cool feature is that current context for the closure can be changed by calling Closure#setDelegate(). This feature will become very important later:
def myClosure = {println myVar} //I'm referencing myVar from MyClass class
MyClass m = new MyClass()
myClosure.setDelegate(m)
myClosure()
class MyClass {
def myVar = 'Hello from MyClass!'
}
at the moment when we created closure, myVar variable doesn't exist. And this is perfectly fine - it should be present in the closure context at the point when we execute this closure.
In this case I modified current context for the closure right before I executed it, so myVar is available.
Pass closure as an argument
The real benefit of having closures - is an ability to pass closure to different methods which helps us to decouple execution logic.
there is (somewhere) a buildscript method which accepts closure:
def buildscript(Closure closure)
there is (somewhere) a allprojects method which accepts closure:
def allprojects(Closure closure)
If we search for buildscript - we will find buildscript {} script block. But wait.. What the hell is script block??? According to documentation:
If we keep reading buildscript documentation - it says: Delegates to: ScriptHandler from buildscript. It means that execution scope for the closure we pass as an input parameter will be changed to ScriptHandler. In our case we passed closure which executes repositories(Closure) and dependencies(Closure) methods. Since closure is delegated to ScriptHandler, let's try to search for dependenciesmethod within ScriptHandler class.
And here it is - void dependencies(Closure configureClosure), which according to documentation, configures dependencies for the script. Here we are seeing another terminology: Executes the given closure against the DependencyHandler. Which means exactly the same as "delegates to [something]" - this closure will be executed in scope of another class (in our case - DependencyHandler)
"delegates to [something]" and "configures [something]" - 2 statements which mean exactly the same - closure will be execute against specified class.
For the sake of completeness, let's see what is happening when we execute closure {classpath 'com.android.tools.build:gradle:1.2.3'} within DependencyHandlercontext. According to documentation this class configures dependencies for given configuration and the syntax should be: <configurationName> <dependencyNotation1>
So with our closure we are configuring configuration with name classpath to use com.android.tools.build:gradle:1.2.3 as a dependency.
task A << {println 'Hello from A'}
task B {
dependsOn A
doLast {
println 'Hello from B'
}
}
That's where mustRunAfter method comes into play. It tells Gradle to run task aftertask specified as an argument. So essentially, we do not introduce dependency between our unit tests and UI tests, but instead we told Gradle to give unit tests priority if they are executed together, so unit tests are executed before our UI test suite:
task unit << {println 'Hello from unit tests'}
task ui << {println 'Hello from UI tests'}
task tests << {println 'Hello from all tests!'}
tests.dependsOn unit
tests.dependsOn ui
ui.mustRunAfter unit
Using the wrapper is the default in Buildship. So this should just work out of the box.
Maybe someone else on your team explicitly set version 2.2 and checked that configuration in? Please reimport the project and double-check on the second wizard page to be sure.
The application plugin adds five tasks to our project:
The run task starts the application.
The startScripts task creates startup scripts to the build/scripts directory. This tasks creates startup scripts for Windows and *nix operating systems.
The installApp task installs the application into the build/install/[project name] directory.
The distZip task creates the binary distribution and packages it into a zip file that is found from the build/distributions directory.
The distTar task creates the binary distribution and packages it into a tar file that is found from the build/distributions directory.
Create the settings.gradle file to the root directory of the root project. A multi-project Gradle build must have this file because it specifies the projects that are included in the multi-project build.
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
testCompile 'junit:junit:4.11'
}
If we want to add common configuration to the subprojects of our root project, we have to add the following snippet to the build.gradle file of our root project:
1
2
3
subprojects {
//Add common configuration here
}
After we have removed the duplicate configuration from the build.gradle file of our root project, it looks as follows:
1
2
3
4
5
6
7
subprojects {
apply plugin: 'java'
repositories {
mavenCentral()
}
}
If we have configuration that is shared by all projects of our multi-project build, we should add the following snippet to the build.gradle file of our root project:
configurations.all {
resolutionStrategy {
// We need this fix: https://github.com/netty/netty/issues/5648
force "io.netty:netty-all:4.0.41.Final"
}
}
// Allows to get the dependency tree for all modules at once with `gw allDeps`
task allDeps(type: DependencyReportTask) {}
}
http://mrhaki.blogspot.com/2016/11/gradle-goodness-replacing-operator-for.html Gradle 3.2 deprecates the << operator to add actions to a task. The << operator maps to the leftShift method of a task. This operator confuses a lot people that are new to Gradle. Because without the operator we are configuring a task instead of adding actions. I can tell from experience the mistake is easily made. If we use the << in our build script with Gradle 3.2 we get a warning on the console. The warning message already mentions a solution: use the doLast method to add actions.
When called gradle allDeps it executes dependencies task on all subprojects.
All dependencies belong to us, but some parts of the tree looks similar (and duplication is a bad thing). Especially configurations default, compile and runtime and the second group testCompile and testRuntime in most cases contain (almost) the same set of dependencies. To make the output shorter we could limit it to runtime (or in case of test dependencies testRuntime). dependencies task provides convenient parameter --configuration and to focus on test dependencies “gradle allDeps --configuration testRuntime” can be used. https://discuss.gradle.org/t/how-to-not-run-checkstyle-findbugs-tasks-automatically/7383/3
I know that I could use the "-x" flag but doign "gradle build -x findbugsMain -x findbugsTest -x checkStyleMain -x checkStyleTest" every time is a bit unwieldy. What I would like to be able to do is to run "gradle build" and not have any of the findbugs or checkstyle tasks run. I would explicitly run the tasks (e. g. "gradle findbugsMain") whenever I would want to analyze the code.
If you didn't set up the IDE project via "Import Project" and then pointing to a Gradle project, you may have to link the IDE project to the Gradle project. This can be done in the "Gradle" window.
Gradle uses a Domain Specific Language (DSL) based on Groovy to declare builds. The DSL provides a flexible language that can be extended by us.
convention-over-configuration
The Gradle Wrapper allows us to execute Gradle builds even if Gradle is not installed on a computer.
gradle -v
If we want to add JVM options to Gradle, we can use the JAVA_OPTS and GRADLE_OPTS environment variables. JAVA_OPTS is a commonly used environment variable name to pass extra parameters to a Java application. Gradle also uses the GRADLE_OPTS environment variable to pass extra arguments to Gradle
Software Development Kit Manager (SDKMAN!)
curl -s get.sdkman.io | bash
sdk install gradle
sdk use gradle 2.12
task helloWorld << {
println 'Hello world.'
}
The << syntax is, an operator shorthand for the leftShift()method, which actually means add to. Therefore, here we are defining that we want to add the closure (with the println 'Hello world' statement) to our task with the helloWorld name.
gradle --quiet helloWorld
Gradle daemon essentially keeps Gradle running in memory so that we don't get the penalty of starting the JVM each time we run Gradle.
Default Gradle tasks
gradle -q tasks
gradle -q help
gradle tasks
gradle -q properties
gradle -q projects
gradle -q model
Closures are basically reusable pieces of code that can be assigned to a variable or passed to a method. A closure is defined by enclosing the piece of code with curly brackets ({... }). We can pass one or more parameters to the closures. If the closure has only one argument, an implicit parameter, it, can be used to reference the parameter value.
task second {
doLast {
// Using implicit 'it' closure parameter.
// The type of 'it' is a Gradle task.
println "Running ${it.name}"
}
}
task second {
doLast { Task task ->
// Using explicit name 'task' as closure parameter.
// We also defined the type of the parameter.
// This can help the IDE to add code completion.
println "Running ${task.name}"
}
}
second.dependsOn 'first'
second.dependsOn = ['first']
task third(dependsOn: 'second') << { task ->
println "Run ${task.name}"
}
task second(dependsOn: first) << printTaskName
second.dependsOn {
// We use the Groovy method findAll
// that returns all tasks that
// apply to the condition we define
// in the closure: the task name
// starts with the letter 'f'.
project.tasks.findAll { task ->
task.name.contains 'f'
}
}
defaultTasks 'first', 'second'
gradle tasks --all