Book Image

Gradle Dependency Management

By : Hubert Klein Ikkink
Book Image

Gradle Dependency Management

By: Hubert Klein Ikkink

Overview of this book

Table of Contents (14 chapters)
Gradle Dependency Management
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Getting information about dependencies


We have seen how we can define dependencies in our build scripts. To get more information about our dependencies, we can use the dependencies task. When we invoke the task, we can see which dependencies belong to the available configurations of our project. Also, any transitive dependencies are shown. The next example build file defines a dependency on Spring beans and we apply the Java plugin. We also specify a repository in the repositories configuration block. We will learn more about repositories in the next chapter. The following code captures the discussion in this paragraph:

apply plugin: 'java'

repositories {
  // Repository definition for JCenter Bintray.
  // Needed to download artifacts. Repository
  // definitions are covered later.
  jcenter()
}

dependencies {
  // Define dependency on spring-beans library.
  compile 'org.springframework:spring-beans:4.0.+'
}

When we execute the dependencies task, we get the following output:

$ gradle -q dependencies

------------------------------------------------------------
Root project
------------------------------------------------------------

archives - Configuration for archive artifacts.
No dependencies

compile - Compile classpath for source set 'main'.
\--- org.springframework:spring-beans:4.0.+ -> 4.0.6.RELEASE
    \--- org.springframework:spring-core:4.0.6.RELEASE
          \--- commons-logging:commons-logging:1.1.3

default - Configuration for default artifacts.
\--- org.springframework:spring-beans:4.0.+ -> 4.0.6.RELEASE
    \--- org.springframework:spring-core:4.0.6.RELEASE
          \--- commons-logging:commons-logging:1.1.3

runtime - Runtime classpath for source set 'main'.
\--- org.springframework:spring-beans:4.0.+ -> 4.0.6.RELEASE
    \--- org.springframework:spring-core:4.0.6.RELEASE
          \--- commons-logging:commons-logging:1.1.3

testCompile - Compile classpath for source set 'test'.
\--- org.springframework:spring-beans:4.0.+ -> 4.0.6.RELEASE
    \--- org.springframework:spring-core:4.0.6.RELEASE
          \--- commons-logging:commons-logging:1.1.3

testRuntime - Runtime classpath for source set 'test'.
\--- org.springframework:spring-beans:4.0.+ -> 4.0.6.RELEASE
    \--- org.springframework:spring-core:4.0.6.RELEASE
          \--- commons-logging:commons-logging:1.1.3

We see all the configurations of our project, and for each configuration, we see the defined dependency with the transitive dependencies. Also, we can see how our dynamic version 4.0.+ is resolved to version 4.0.6.RELEASE. To only see dependencies for a specific configuration, we can use the --configuration option for the dependencies task. We must use the value of the configuration we want to see the dependencies for. In the following output, we see the result when we only want to see the dependencies for the compile configuration:

$ gradle -q dependencies --configuration compile

------------------------------------------------------------
Root project
------------------------------------------------------------

compile - Compile classpath for source set 'main'.
\--- org.springframework:spring-beans:4.0.+ -> 4.0.6.RELEASE
    \--- org.springframework:spring-core:4.0.6.RELEASE
          \--- commons-logging:commons-logging:1.1.3

There is also the dependencyInsight incubating task in Gradle. Because it is incubating, the functionality or syntax can change in future versions of Gradle. With the dependencyInsight task, we can find out why a specific dependency is in our build and to which configuration it belongs. We have to use the --dependency option, the required one, with part of the name of the dependency. Gradle will look for dependencies where the group, name, or version contains part of the specified value for the --dependency option. Optionally, we can specify the --configuration option to only look for the dependency in the specified configuration. If we leave out this option, Gradle will look for the dependency in all the configurations of our project.

Let's invoke the dependencyInsight task to find the dependencies with Spring in the name and in the runtime configuration:

$ gradle -q dependencyInsight --dependency spring --configuration runtime
org.springframework:spring-beans:4.0.6.RELEASE

org.springframework:spring-beans:4.0.+ -> 4.0.6.RELEASE
\--- runtime

org.springframework:spring-core:4.0.6.RELEASE
\--- org.springframework:spring-beans:4.0.6.RELEASE
    \--- runtime

In the output, we see how version 4.0.+ is resolved to 4.0.6.RELEASE. We also see that the spring-beans dependency and the transitive spring-core dependency are part of the runtime configuration.

Accessing dependencies

To access the configurations, we can use the configurations property of the Gradle project object. The configurations property contains a collection of Configuration objects. It is good to remember that a Configuration object is an instance of FileCollection. So, we can reference Configuration in our build scripts where FileCollection is allowed. The Configuration object contains more properties we can use to access the dependencies belonging to the configuration.

In the next example build, we will define two tasks that work with the files and information available from configurations in the project:

configurations {
  vehicles
  traffic.extendsFrom vehicles
}

task dependencyFiles << {
  // Loop through all files for the dependencies
  // for the traffic configuration, including
  // transitive dependencies.
  configurations.traffic.files.each { file ->
    println file.name
  }

  // We can also filter the files using
  // a closure. For example to only find the files
  // for dependencies with driver in the name.
  configurations.vehicles.files { dep ->
    if (dep.name.contains('driver')) {
      println dep.name
    }
  }

  // Get information about dependencies only belonging
  // to the vehicles configuration.
  configurations.vehicles.dependencies.each { dep ->
    println "${dep.group} / ${dep.name} / ${dep.version}"
  }

  // Get information about dependencies belonging
  // to the traffice configuration and
  // configurations it extends from.
  configurations.traffic.allDependencies.each {  dep ->
    println "${dep.group} / ${dep.name} / ${dep.version}"
  }
}

task copyDependencies(type: Copy) {
  description = 'Copy dependencies from configuration traffic to lib directory'

  // Configuration can be the source for a CopySpec.
  from configurations.traffic

  into "$buildDir/lib"
}

Buildscript dependencies

When we define dependencies, we mostly want to define them for the code we are developing. However, we may also want to add a dependency to the Gradle build script itself. We can write code in our build files, which might be dependent on a library that is not included in the Gradle distribution. Let's suppose we want to use a class from the Apache Commons Lang library in our build script. We must add a buildscript configuration closure to our build script. Within the configuration closure, we can define repositories and dependencies. We must use the special classpath configuration to add dependencies to. Any dependency added to the classpath configuration can be used by the code in our build file.

Let's see how this works with an example build file. We want to use the org.apache.commons.lang3.RandomStringUtils class inside a randomString task. This class can be found in the org.apache.commons:commons-lang3 dependency. We define this as an external dependency for the classpath configuration. We also include a repository definition inside the buildscript configuration block so that the dependency can be downloaded. The following code shows this:

buildscript {
  repositories {
    // Bintray JCenter repository to download
    // dependency commons-lang3.
    jcenter()
  }

  dependencies {
    // Extend classpath of build script with
    // the classpath configuration.
    classpath 'org.apache.commons:commons-lang3:3.3.2'
  }
}

// We have add the commons-lang3 dependency
// as a build script dependency so we can
// reference classes for Apache Commons Lang.
import org.apache.commons.lang3.RandomStringUtils

task randomString << {
  // Use RandomStringUtils from Apache Commons Lang.
  String value = RandomStringUtils.randomAlphabetic(10)
  println value
}

To include external plugins, which are not part of the Gradle distribution, we can also use the classpath configuration in the buildscript configuration block. In the next example build file, we will include the Asciidoctor Gradle plugin:

buildscript {
  repositories {
    // We need the repository definition, from
    // where the dependency can be downloaded.
    jcenter()
  }

  dependencies {
    // Define external module dependency for the Gradle
    // Asciidoctor plugin.
    classpath 'org.asciidoctor:asciidoctor-gradle-plugin:0.7.3'
  }
}

// We defined the dependency on this external
// Gradle plugin in the buildscript {...}
// configuration block
apply plugin: 'org.asciidoctor.gradle.asciidoctor'