// Copyright 2018 the original author or authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[inspecting_dependencies]]
= Inspecting Dependencies

Gradle provides sufficient tooling to navigate large dependency graphs and mitigate situations that can lead to link:https://en.wikipedia.org/wiki/Dependency_hell[dependency hell]. Users can choose to render the full graph of dependencies as well as identify the selection reason and origin for a dependency. The origin of a dependency can be a declared dependency in the build script or a transitive dependency in graph plus their corresponding configuration. Gradle offers both capabilities through visual representation via build scans and as command line tooling.

[[sec:listing_dependencies]]
== Listing dependencies in a project

A project can declare one or more dependencies. Gradle can visualize the whole dependency tree for every <<managing_dependency_configurations.adoc#sub:what_is_a_configuration,configuration>> available in the project.

Rendering the dependency tree is particularly useful if you'd like to identify which dependencies have been resolved at runtime. It also provides you with information about any dependency conflict resolution that occurred in the process and clearly indicates the selected version. The dependency report always contains declared and transitive dependencies.

Let's say you'd want to create tasks for your project that use the link:https://www.eclipse.org/jgit/[JGit library] to execute SCM operations e.g. to model a release process. You can declare dependencies for any external tooling with the help of a <<managing_dependency_configurations.adoc#managing_dependency_configurations,custom configuration>> so that it doesn't pollute other contexts like the compilation classpath for your production source code.

.Declaring the JGit dependency with a custom configuration
====
include::sample[dir="userguide/dependencyManagement/inspectingDependencies/dependenciesReport/groovy",files="build.gradle[tags=dependency-declaration]"]
include::sample[dir="userguide/dependencyManagement/inspectingDependencies/dependenciesReport/kotlin",files="build.gradle.kts[tags=dependency-declaration]"]
====

A link:https://scans.gradle.com/[build scan] can visualize dependencies as a navigable, searchable tree. Additional context information can be rendered by clicking on a specific dependency in the graph.

.Dependency tree in a build scan
image::dependency-management-dependencies-report-build-scan.png[]

Every Gradle project provides the task `dependencies` to render the so-called _dependency report_ from the command line. By default the dependency report renders dependencies for all configurations. To pair down on the information provide the optional parameter `--configuration`.

=== Example: Rendering the dependency report for a custom configuration

.Output of **`gradle -q dependencies --configuration scm`**
----
> gradle -q dependencies --configuration scm
include::{samplesPath}/userguide/dependencyManagement/inspectingDependencies/dependenciesReport/dependencyReport.out[]
----

The dependencies report provides detailed information about the dependencies available in the graph. Any dependency that could not be resolved is marked with `FAILED` in red color. Dependencies with the same coordinates that can occur multiple times in the graph are omitted and indicated by an asterisk. Dependencies that had to undergo conflict resolution render the requested and selected version separated by a right arrow character.

[[sec:identifying_reason_dependency_selection]]
== Identifying which dependency version was selected and why

Large software projects inevitably deal with an increased number of dependencies either through direct or transitive dependencies. The <<#sec:listing_dependencies,dependencies report>> provides you with the raw list of dependencies but does not explain _why_ they have been selected or _which_ dependency is responsible for pulling them into the graph.

Let's have a look at a concrete example. A project may request two different versions of the same dependency either as direct or transitive dependency. Gradle applies version conflict resolution to ensure that only one version of the dependency exists in the dependency graph. In this example the conflicting dependency is represented by `commons-codec:commons-codec`.

.Declaring the JGit dependency and a conflicting dependency
====
include::sample[dir="userguide/dependencyManagement/inspectingDependencies/dependencyInsightReport/groovy",files="build.gradle[tags=dependency-declaration]"]
include::sample[dir="userguide/dependencyManagement/inspectingDependencies/dependencyInsightReport/kotlin",files="build.gradle.kts[tags=dependency-declaration]"]
====

The dependency tree in a link:https://scans.gradle.com/[build scan] renders the selection reason (conflict resolution) as well as the origin of a dependency if you click on a dependency and select the "Required By" tab.

.Dependency insight capabilities in a build scan
image::dependency-management-dependency-insight-report-build-scan.png[]

Every Gradle project provides the task `dependencyInsight` to render the so-called  _dependency insight report_ from the command line. Given a dependency in the dependency graph you can identify the selection reason and track down the origin of the dependency selection. You can think of the dependency insight report as the inverse representation of the dependency report for a given dependency. When executing the task you have to provide the mandatory parameter `--dependency` to specify the coordinates of the dependency under inspection. The parameters `--configuration` and `--singlepath` are optional but help with filtering the output.

=== Example: Using the dependency insight report for a given dependency

.Output of **`gradle -q dependencyInsight --dependency commons-codec --configuration scm`**
----
> gradle -q dependencyInsight --dependency commons-codec --configuration scm
include::{samplesPath}/userguide/dependencyManagement/inspectingDependencies/dependencyInsightReport/dependencyInsightReport.out[]
----

[[sec:dependency_declaration_reasons]]
== Justifying dependency declarations with custom reasons

When you declare a <<declaring_dependencies.adoc#declaring_dependencies,dependency>> or a <<managing_transitive_dependencies.adoc#sec:dependency_constraints,dependency constraint>>, you can provide a custom reason for the declaration. This makes the dependency declarations in your build script and the dependency insight report easier to interpret.

.Giving a reason for choosing a certain module version in a dependency declaration
====
include::sample[dir="userguide/dependencyManagement/inspectingDependencies/dependencyReason/groovy",files="build.gradle[tags=dependency-reason]"]
include::sample[dir="userguide/dependencyManagement/inspectingDependencies/dependencyReason/kotlin",files="build.gradle.kts[tags=dependency-reason]"]
====

=== Example: Using the dependency insight report with custom reasons

.Output of **`gradle -q dependencyInsight --dependency asm`**
----
> gradle -q dependencyInsight --dependency asm
include::{samplesPath}/userguide/dependencyManagement/inspectingDependencies/dependencyReason/dependencyReasonReport.out[]
----
