- Purpose
- Usage
- Why the change?
- The
lock
extension method - The
updateLocks
task - Ignoring locks
- Migration from the legacy plugin
- What about locking transitives?
This project is an experimental major overhaul of the gradle-dependency-lock-plugin.
Clone and build with:
./gradlew publishToMavenLocal
To apply this plugin:
buildscript {
repositories { mavenLocal() }
dependencies {
classpath 'io.spring.gradle:dependency-lock:latest.release'
}
configurations.classpath.resolutionStrategy.cacheDynamicVersionsFor 0, 'minutes'
}
apply plugin: 'spring.lock'
We believe this is the real root use case for dependency locks: "I want to write static versions into my dependency blocks, but I don't want to have to manually update the static versions as new versions come out."
-
At various times, gradle-dependency-lock-plugin served functions that are now best served by other means, e.g. version alignment which is now satisfied by gradle-resolution-rules.
-
dependencies.lock is hard to read and separate from where users define their dependencies in build.gradle. Unaware that nebula.dependency-lock is in effect, engineers are often confused about why they don't get a certain version when they update build.gradle.
-
Manually updating a particular dependency while leaving the rest locked requires a priori knowledge of the existence of the
./gradlew updateLock -PdependencyLock.updateDependencies=com.example:foo,com.example:bar
mechanism. Well-meaning engineers may attempt to update dependencies.lock manually, not realizing that the dependency they are attempting to update is reflected once for each configuration it appears in, and their manual effort fails to achieve their goal. -
nebula.dependency-lock applies its locks using
resolutionStrategy.force
, which can lead to ordering problems with other plugins that affectresolutionStrategy
.
compile 'com.google.guava:guava:latest.release' lock '19.0'
The experimental plugin hangs a method on org.gradle.api.artifacts.Dependency
called lock
that takes a single String
parameter with
the locked version. The lock
method receives the Dependency
created and immediately substitutes it with a Dependency
with the locked version.
This happens before any other dependency-affecting event in the Gradle ecosystem.
In effect, lock
makes it seem to Gradle that rather than writing a dynamic constraint like latest.release you had actually just written
in a fixed version.
If you want to just update a single dependency, rather than running ``./gradlew updateLock -PdependencyLock.updateDependencies=..., you can simply change the text of the
lock` in build.gradle.
Running ./gradlew updateLocks
resolves each configuration without locks, and uses an AST parser to locate first order
dependencies in your build.gradle and write out the appropriate lock
method call with the resolved version. updateLocks
also detects if you change the unlocked version to a static constraint and removes the lock
method call.
In the case of a dependency specified in a root project, e.g.
subprojects {
dependencies {
compile 'com.google.guava:guava:latest.release'
}
}
the updateLocks
task will evaluate the resolved configuration for each of the subprojects and lock at the highest dependency found.
Because Gradle returns null
from a method call like
compile 'com.google.guava:19.+',
'commons-lang:commons-lang:2.+'
the task will generate the following:
compile 'com.google.guava:19.+' lock '19.0'
compile 'commons-lang:commons-lang:2.+' lock '2.6'
Running with -PdependencyLock.ignore
causes the lock method to short-circuit and leave dynamic constraints in effect.
We no longer believe there are any reasons to lock transitive dependencies, because
- The vast majority of Java libraries are published with fixed versions (and Gradle does not support Ivy's
revConstraint
) - Responsibility for version alignment has been externalized to gradle-resolution-rules.