- Purpose
- Usage
- Why the change?
- The
lockextension method - The
updateLockstask - 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:barmechanism. 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.