// Copyright (C) 2023 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.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.

[[dependency-constraints]]
= Upgrading versions of transitive dependencies

[[sec:direct-vs-transitive-deps]]
== Direct dependencies vs dependency constraints

A component may have two different kinds of dependencies:

- direct dependencies are _directly required by the component_.
A direct dependency is also referred to as a _first level dependency_.
For example, if your project source code requires Guava, Guava should be declared as _direct dependency_.
- transitive dependencies are dependencies that your component needs, but only because another dependency needs them.

It's quite common that issues with dependency management are about _transitive dependencies_.
Often developers incorrectly fix transitive dependency issues by adding _direct dependencies_.
To avoid this, Gradle provides the concept of _dependency constraints_.

[[sec:adding-constraints-transitive-deps]]
== Adding constraints on transitive dependencies

Dependency constraints allow you to define the version or the version range of both dependencies declared in the build script and transitive dependencies.
It is the preferred method to express constraints that should be applied to all dependencies of a configuration.
When Gradle attempts to resolve a dependency to a module version, all <<rich_versions.adoc#rich-version-constraints,dependency declarations with version>>, all transitive dependencies and all dependency constraints for that module are taken into consideration.
The highest version that matches all conditions is selected.
If no such version is found, Gradle fails with an error showing the conflicting declarations.
If this happens you can adjust your dependencies or dependency constraints declarations, or make other adjustments to the transitive dependencies if needed.
Similar to dependency declarations, dependency constraint declarations are <<declaring_dependencies.adoc#sec:what-are-dependency-configurations,scoped by configurations>> and can therefore be selectively defined for parts of a build.
If a dependency constraint influenced the resolution result, any type of <<resolution_rules.adoc#sec:dependency_resolve_rules,dependency resolve rules>> may still be applied afterwards.

.Define dependency constraints
====
include::sample[dir="snippets/dependencyManagement/managingTransitiveDependencies-versionsWithConstraints/kotlin",files="build.gradle.kts[tags=dependency-constraints]"]
include::sample[dir="snippets/dependencyManagement/managingTransitiveDependencies-versionsWithConstraints/groovy",files="build.gradle[tags=dependency-constraints]"]
====

In the example, all versions are omitted from the dependency declaration.
Instead, the versions are defined in the constraints block.
The version definition for `commons-codec:1.11` is only taken into account if `commons-codec` is brought in as transitive dependency, since `commons-codec` is not defined as dependency in the project.
Otherwise, the constraint has no effect.
Dependency constraints can also define a <<rich_versions.adoc#rich-version-constraints,rich version constraint>> and support <<rich_versions.adoc#sec:strict-version,strict versions>> to enforce a version even if it contradicts with the version defined by a transitive dependency (e.g. if the version needs to be downgraded).

NOTE: Dependency constraints are only published when using <<publishing_gradle_module_metadata.adoc#sec:understanding-gradle-module-md,Gradle Module Metadata>>.
This means that currently they are only fully supported if Gradle is used for publishing and consuming (i.e. they are 'lost' when consuming modules with Maven or Ivy).

Dependency constraints themselves can also be added transitively.
