I am trying to apply dependency locking to my Java web project. The project has varying configurations depending on the target customer/environment. Up until now, we’ve had
dependencies {
....
if (project.customer='X') {
runtime 'org.springframework.security.kerberos:spring-security-kerberos-web:latest.release'
}
...
}
That didn’t work with dependency locking: generating the dependency locks for a build for customer X caused the build for customer Y to fail because of missing or extra dependencies.
We have now modified this, adding a custom configuration for each customer:
configurations {
defaultRuntime
customerX.extendsFrom defaultRuntime
customerY.extendsFrom defaultRuntime
}
and our dependencies block now says
dependencies {
compile group: 'org.springframework', name: 'spring-context', version: 'latest.release', transitive:false
....
defaultRuntime group: 'org.springframework', name:'spring-aop', version:'latest.release', transitive:false
customerX 'org.springframework.security.kerberos:spring-security-kerberos-web:latest.release'
runtime configurations["customer${project.customer}"] // This is the *only* dependency specification for "runtime"
}
We exclude “runtime*” (and “testRuntime*”) from dependency locking, but lock everything else.
The problem: “runtime” pulls in latest.release of all the dependencies, not the locked version from the customer configuration:
./gradlew :web_client:dependencyinsight --dependency org.springframework:spring-beans --configuration customerdemo
results in
org.springframework:spring-beans:4.3.23.RELEASE
variant "runtime" [
org.gradle.status = release (not requested)
org.gradle.usage = java-runtime (not requested)
org.gradle.category = library (not requested)
]
Selection reasons:
- By constraint : dependency was locked to version '4.3.23.RELEASE'
org.springframework:spring-beans:{strictly 4.3.23.RELEASE} -> 4.3.23.RELEASE
\--- customerdemo
org.springframework:spring-beans:4.3.23.RELEASE
+--- org.springframework:spring-oxm:4.3.23.RELEASE
| +--- customerdemo (requested org.springframework:spring-oxm:{strictly 4.3.23.RELEASE})
| \--- project :mock_daos (requested org.springframework:spring-oxm:latest.release)
| \--- customerdemo
\--- org.springframework:spring-tx:4.3.23.RELEASE
+--- customerdemo (requested org.springframework:spring-tx:{strictly 4.3.23.RELEASE})
\--- project :mock_daos (requested org.springframework:spring-tx:latest.release) (*)
(*) - dependencies omitted (listed previously)
but
/gradlew :web_client:dependencyinsight --dependency org.springframework:spring-beans --configuration runtime
results in
> Task :web_client:dependencyInsight
org.springframework:spring-beans:5.1.6.RELEASE
variant "runtime" [
org.gradle.status = release (not requested)
org.gradle.usage = java-runtime (not requested)
org.gradle.category = library (not requested)
]
org.springframework:spring-beans:5.1.6.RELEASE
+--- org.springframework:spring-aop:5.1.6.RELEASE
| +--- org.springframework.security:spring-security-web:5.1.5.RELEASE
| | \--- runtime (requested org.springframework.security:spring-security-web:latest.release)
| +--- org.springframework.security:spring-security-config:5.1.5.RELEASE
| | \--- runtime (requested org.springframework.security:spring-security-config:latest.release)
| +--- org.springframework.security:spring-security-core:5.1.5.RELEASE
| | +--- org.springframework.security:spring-security-web:5.1.5.RELEASE (*)
| | \--- org.springframework.security:spring-security-config:5.1.5.RELEASE (*)
| \--- org.springframework:spring-context:5.1.6.RELEASE
| +--- runtime (requested org.springframework:spring-context:latest.release)
| +--- org.springframework.security:spring-security-web:5.1.5.RELEASE (*)
| +--- org.springframework.security:spring-security-config:5.1.5.RELEASE (*)
| \--- org.springframework.security:spring-security-core:5.1.5.RELEASE (*)
+--- org.springframework:spring-context:5.1.6.RELEASE (*)
+--- org.springframework:spring-web:5.1.6.RELEASE
| +--- runtime (requested org.springframework:spring-web:latest.release)
| \--- org.springframework.security:spring-security-web:5.1.5.RELEASE (*)
+--- org.springframework.security:spring-security-config:5.1.5.RELEASE (*)
+--- org.springframework.security:spring-security-core:5.1.5.RELEASE (*)
\--- org.springframework.security:spring-security-web:5.1.5.RELEASE (*)
org.springframework:spring-beans:latest.release -> 5.1.6.RELEASE
\--- project :service_core
\--- runtime
(*) - dependencies omitted (listed previously)
Additionally (just to make it clear that service_core.runtime is also a locked version):
./gradlew :service_core:dependencyinsight --dependency org.springframework:spring-beans --configuration runtime
results in
> Task :service_core:dependencyInsight
org.springframework:spring-beans:4.3.23.RELEASE
variant "runtime" [
org.gradle.status = release (not requested)
org.gradle.usage = java-runtime (not requested)
org.gradle.category = library (not requested)
]
Selection reasons:
- Was requested : rejected versions 5.1.6.RELEASE, 5.1.5.RELEASE, 5.1.4.RELEASE, 5.1.3.RELEASE, 5.1.2.RELEASE, 5.1.1.RELEASE, 5.1.0.RELEASE, 5.0.13.RELEASE, 5.0.12.RELEASE, 5.0.11.RELEASE, 5.0.10.RELEASE, 5.0.9.RELEASE, 5.0.8.RELEASE, 5.0.7.RELEASE, 5.0.6.RELEASE, 5.0.5.RELEASE, 5.0.4.RELEASE, 5.0.3.RELEASE, 5.0.2.RELEASE, 5.0.1.RELEASE, 5.0.0.RELEASE
- By constraint : dependency was locked to version '4.3.23.RELEASE'
org.springframework:spring-beans:{strictly 4.3.23.RELEASE} -> 4.3.23.RELEASE
\--- runtime
org.springframework:spring-beans:latest.release -> 4.3.23.RELEASE
\--- runtime
So all of the locked configurations (web_client.compile, web_client.customerdemo, service_core:runtime etc.) correctly select the locked dependency version. The un-lockable web_client.runtime configuration ignores all that and picks latest.release.
Is that expected behaviour? If so, what is a usable strategy to lock dependencies with customer-specific artefacts?