Declaring Versions and Ranges
The simplest version declaration is a simple string representing the version to use. Gradle supports different ways of declaring a version string:
-
An exact version: e.g.
1.3
,1.3.0-beta3
,1.0-20150201.131010-1
-
A Maven-style version range: e.g.
[1.0,)
,[1.1, 2.0)
,(1.2, 1.5]
-
The
[
and]
symbols indicate an inclusive bound;(
and)
indicate an exclusive bound. -
When the upper or lower bound is missing, the range has no upper or lower bound.
-
The symbol
]
can be used instead of(
for an exclusive lower bound, and[
instead of)
for exclusive upper bound. e.g]1.0, 2.0[
-
-
A prefix version range: e.g.
1.+
,1.3.+
-
Only versions exactly matching the portion before the
+
are included. -
The range
+
on it’s own will include any version.
-
-
A
latest-status
version: e.g.latest.integration
,latest.release
-
Will match the highest versioned module with the specified status. See ComponentMetadata.getStatus().
-
-
A Maven
SNAPSHOT
version identifier: e.g.1.0-SNAPSHOT
,1.4.9-beta1-SNAPSHOT
Gradle 6.5 supports an alternate, opt-in, behaviour for version ranges. When an upper bound excludes a version, it also acts as a prefix exclude.
This means that Activating the feature preview
This change will become the default in Gradle 7.0. |
Version ordering
Versions have an implicit ordering. Version ordering is used to:
-
Determine if a particular version is included in a range.
-
Determine which version is 'newest' when performing conflict resolution.
Versions are ordered based on the following rules:
-
Each version is split into it’s constituent "parts":
-
The characters
[. - _ +]
are used to separate the different "parts" of a version. -
Any part that contains both digits and letters is split into separate parts for each:
1a1 == 1.a.1
-
Only the parts of a version are compared. The actual separator characters are not significant:
1.a.1 == 1-a+1 == 1.a-1 == 1a1
-
-
The equivalent parts of 2 versions are compared using the following rules:
-
If both parts are numeric, the highest numeric value is higher:
1.1
<1.2
-
If one part is numeric, it is considered higher than the non-numeric part:
1.a
<1.1
-
If both are not numeric, the parts are compared alphabetically, case-sensitive:
1.A
<1.B
<1.a
<1.b
-
A version with an extra numeric part is considered higher than a version without:
1.1
<1.1.0
-
A version with an extra non-numeric part is considered lower than a version without:
1.1.a
<1.1
-
-
Certain string values have special meaning for the purposes of ordering:
-
The string
dev
is consider lower than any other string part:1.0-dev
<1.0-alpha
<1.0-rc
. -
The strings
rc
,release
andfinal
are considered higher than any other string part (sorted in that order):1.0-zeta
<1.0-rc
<1.0-release
<1.0-final
<1.0
. -
The string
SNAPSHOT
has no special meaning, and is sorted alphabetically like any other string part:1.0-alpha
<1.0-SNAPSHOT
<1.0-zeta
<1.0-rc
<1.0
. -
Numeric snapshot versions have no special meaning, and are sorted like any other numeric part:
1.0
<1.0-20150201.121010-123
<1.1
.
-
Gradle 6.5 supports an alternate, opt-in, version ordering scheme which special cases more suffixes:
Activating the feature preview
These changes will become the default in Gradle 7.0. |
Simple version declaration semantics
When you declare a version using the short-hand notation, for example:
dependencies {
implementation('org.slf4j:slf4j-api:1.7.15')
}
dependencies {
implementation("org.slf4j:slf4j-api:1.7.15")
}
Then the version is considered a required version which means that it should minimally be 1.7.15
but can be upgraded by the engine (optimistic upgrade).
There is, however, a shorthand notation for strict versions, using the !!
notation:
dependencies {
// short-hand notation with !!
implementation('org.slf4j:slf4j-api:1.7.15!!')
// is equivalent to
implementation("org.slf4j:slf4j-api") {
version {
strictly '1.7.15'
}
}
// or...
implementation('org.slf4j:slf4j-api:[1.7, 1.8[!!1.7.25')
// is equivalent to
implementation('org.slf4j:slf4j-api') {
version {
strictly '[1.7, 1.8['
prefer '1.7.25'
}
}
}
dependencies {
// short-hand notation with !!
implementation("org.slf4j:slf4j-api:1.7.15!!")
// is equivalent to
implementation("org.slf4j:slf4j-api") {
version {
strictly("1.7.15")
}
}
// or...
implementation("org.slf4j:slf4j-api:[1.7, 1.8[!!1.7.25")
// is equivalent to
implementation("org.slf4j:slf4j-api") {
version {
strictly([1.7, 1.8[")
prefer("1.7.25")
}
}
}
A strict version cannot be upgraded and overrides whatever transitive dependencies originating from this dependency provide. It is recommended to use ranges for strict versions.
The notation [1.7, 1.8[!!1.7.25
above is equivalent to:
-
strictly
[1.7, 1.8[
-
prefer
1.7.25
which means that the engine must select a version between 1.7 (included) and 1.8 (excluded), and that if no other component in the graph needs a different version, it should prefer 1.7.25
.
Declaring a dependency without version
A recommended practice for larger projects is to declare dependencies without versions and use dependency constraints for version declaration. The advantage is that dependency constraints allow you to manage versions of all dependencies, including transitive ones, in one place.
dependencies {
implementation 'org.springframework:spring-web'
}
dependencies {
constraints {
implementation 'org.springframework:spring-web:5.0.2.RELEASE'
}
}
dependencies {
implementation("org.springframework:spring-web")
}
dependencies {
constraints {
implementation("org.springframework:spring-web:5.0.2.RELEASE")
}
}