mirror of https://github.com/grpc/grpc-java.git
Replace failOnVersionConflict() with custom requireUpperBoundDeps
failOnVersionConflict has never been good for us. It is equivalent to Maven dependencyConvergence which we discourage our users to use because it is too tempermental and _creates_ version skew issues over time. However, we had no real alternative for determining if our deps would be misinterpeted by Maven. failOnVersionConflict has been a constant drain and makes it really hard to do seemingly-trivial upgrades. As evidenced by protobuf/build.gradle in this change, it also caused _us_ to introduce a version downgrade. This introduces our own custom requireUpperBoundDeps implementation so that we can get back to simple dependency upgrades _and_ increase our confidence in a consistent dependency tree.
This commit is contained in:
parent
aa18b2c228
commit
5642e01243
|
@ -21,10 +21,10 @@ dependencies {
|
|||
project(':grpc-protobuf'),
|
||||
project(':grpc-stub'),
|
||||
libraries.protobuf,
|
||||
libraries.conscrypt
|
||||
libraries.conscrypt,
|
||||
libraries.guava,
|
||||
libraries.google_auth_oauth2_http
|
||||
def nettyDependency = implementation project(':grpc-netty')
|
||||
googleOauth2Dependency 'implementation'
|
||||
guavaDependency 'implementation'
|
||||
compileOnly libraries.javax_annotation
|
||||
|
||||
shadow configurations.implementation.getDependencies().minus(nettyDependency)
|
||||
|
|
|
@ -63,12 +63,12 @@ dependencies {
|
|||
project(':grpc-stub'),
|
||||
project(':grpc-testing'),
|
||||
libraries.junit,
|
||||
libraries.truth
|
||||
libraries.truth,
|
||||
libraries.opencensus_contrib_grpc_metrics
|
||||
|
||||
implementation (libraries.google_auth_oauth2_http) {
|
||||
exclude group: 'org.apache.httpcomponents'
|
||||
}
|
||||
censusGrpcMetricDependency 'implementation'
|
||||
|
||||
compileOnly libraries.javax_annotation
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
api project(':grpc-core')
|
||||
guavaDependency 'implementation'
|
||||
implementation libraries.guava
|
||||
testImplementation project('::grpc-okhttp')
|
||||
testImplementation libraries.androidx_test
|
||||
testImplementation libraries.junit
|
||||
|
|
|
@ -13,7 +13,8 @@ evaluationDependsOn(project(':grpc-context').path)
|
|||
dependencies {
|
||||
api project(':grpc-context'),
|
||||
libraries.jsr305
|
||||
guavaDependency 'implementation'
|
||||
implementation libraries.guava,
|
||||
libraries.errorprone
|
||||
|
||||
testImplementation project(':grpc-context').sourceSets.test.output,
|
||||
project(':grpc-testing'),
|
||||
|
|
|
@ -10,9 +10,9 @@ description = "gRPC: Auth"
|
|||
dependencies {
|
||||
api project(':grpc-api'),
|
||||
libraries.google_auth_credentials
|
||||
guavaDependency 'implementation'
|
||||
testImplementation project(':grpc-testing')
|
||||
googleOauth2Dependency 'testImplementation'
|
||||
implementation libraries.guava
|
||||
testImplementation project(':grpc-testing'),
|
||||
libraries.google_auth_oauth2_http
|
||||
signature "org.codehaus.mojo.signature:java17:1.0@signature"
|
||||
signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature"
|
||||
}
|
||||
|
|
|
@ -47,9 +47,9 @@ repositories {
|
|||
dependencies {
|
||||
api project(':grpc-core')
|
||||
|
||||
guavaDependency 'implementation'
|
||||
implementation libraries.androidx_annotation
|
||||
implementation libraries.androidx_core
|
||||
implementation libraries.guava
|
||||
testImplementation libraries.androidx_core
|
||||
testImplementation libraries.androidx_test
|
||||
testImplementation libraries.junit
|
||||
|
|
147
build.gradle
147
build.gradle
|
@ -205,68 +205,6 @@ subprojects {
|
|||
jetty_alpn_agent: 'org.mortbay.jetty.alpn:jetty-alpn-agent:2.0.10'
|
||||
]
|
||||
|
||||
// A util function to config guava dependency with transitive dependencies
|
||||
// properly resolved for the failOnVersionConflict strategy.
|
||||
guavaDependency = { configurationName ->
|
||||
dependencies."$configurationName"(libraries.guava) {
|
||||
exclude group: 'com.google.code.findbugs', module: 'jsr305'
|
||||
exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
|
||||
exclude group: 'org.codehaus.mojo', module: 'animal-sniffer-annotations'
|
||||
}
|
||||
dependencies."$configurationName" libraries.errorprone
|
||||
dependencies.runtimeOnly libraries.animalsniffer_annotations
|
||||
dependencies.runtimeOnly libraries.jsr305
|
||||
}
|
||||
|
||||
// A util function to config opencensus_api dependency with transitive
|
||||
// dependencies properly resolved for the failOnVersionConflict strategy.
|
||||
censusApiDependency = { configurationName ->
|
||||
dependencies."$configurationName"(libraries.opencensus_api) {
|
||||
exclude group: 'com.google.code.findbugs', module: 'jsr305'
|
||||
exclude group: 'com.google.guava', module: 'guava'
|
||||
// we'll always be more up-to-date
|
||||
exclude group: 'io.grpc', module: 'grpc-context'
|
||||
}
|
||||
dependencies.runtimeOnly project(':grpc-context')
|
||||
dependencies.runtimeOnly libraries.jsr305
|
||||
guavaDependency 'runtimeOnly'
|
||||
}
|
||||
|
||||
// A util function to config opencensus_contrib_grpc_metrics dependency
|
||||
// with transitive dependencies properly resolved for the failOnVersionConflict
|
||||
// strategy.
|
||||
censusGrpcMetricDependency = { configurationName ->
|
||||
dependencies."$configurationName"(libraries.opencensus_contrib_grpc_metrics) {
|
||||
exclude group: 'com.google.code.findbugs', module: 'jsr305'
|
||||
exclude group: 'com.google.guava', module: 'guava'
|
||||
// we'll always be more up-to-date
|
||||
exclude group: 'io.grpc', module: 'grpc-context'
|
||||
}
|
||||
dependencies.runtimeOnly project(':grpc-context')
|
||||
dependencies.runtimeOnly libraries.jsr305
|
||||
guavaDependency 'runtimeOnly'
|
||||
}
|
||||
|
||||
googleOauth2Dependency = { configurationName ->
|
||||
dependencies."$configurationName"(libraries.google_auth_oauth2_http) {
|
||||
exclude group: 'com.google.guava', module: 'guava'
|
||||
exclude group: 'io.grpc', module: 'grpc-context'
|
||||
exclude group: 'io.opencensus', module: 'opencensus-api'
|
||||
}
|
||||
dependencies.runtimeOnly project(':grpc-context')
|
||||
censusApiDependency 'runtimeOnly'
|
||||
guavaDependency 'runtimeOnly'
|
||||
}
|
||||
|
||||
// A util function to config perfmark dependency with transitive
|
||||
// dependencies properly resolved for the failOnVersionConflict strategy.
|
||||
perfmarkDependency = { configurationName ->
|
||||
dependencies."$configurationName"(libraries.perfmark) {
|
||||
exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
|
||||
}
|
||||
dependencies.runtimeOnly libraries.errorprone
|
||||
}
|
||||
|
||||
appendToProperty = { Property<String> property, String value, String separator ->
|
||||
if (property.present) {
|
||||
property.set(property.get() + separator + value)
|
||||
|
@ -276,25 +214,6 @@ subprojects {
|
|||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
// Detect Maven Enforcer's dependencyConvergence failures. We only
|
||||
// care for artifacts used as libraries by others.
|
||||
if (isAndroid && !(project.name in ['grpc-android-interop-testing'])) {
|
||||
releaseRuntimeClasspath {
|
||||
resolutionStrategy.failOnVersionConflict()
|
||||
}
|
||||
}
|
||||
if (!isAndroid && !(project.name in [
|
||||
'grpc-benchmarks',
|
||||
'grpc-interop-testing',
|
||||
'grpc-gae-interop-testing-jdk8',
|
||||
])) {
|
||||
runtimeClasspath {
|
||||
resolutionStrategy.failOnVersionConflict()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disable JavaDoc doclint on Java 8. It's annoying.
|
||||
if (JavaVersion.current().isJava8Compatible()) {
|
||||
allprojects {
|
||||
|
@ -406,6 +325,19 @@ subprojects {
|
|||
}
|
||||
}
|
||||
|
||||
plugins.withId("java-library") {
|
||||
// Detect Maven Enforcer's dependencyConvergence failures. We only care
|
||||
// for artifacts used as libraries by others with Maven.
|
||||
tasks.register('checkUpperBoundDeps') {
|
||||
doLast {
|
||||
requireUpperBoundDepsMatch(configurations.runtimeClasspath, project)
|
||||
}
|
||||
}
|
||||
tasks.named('compileJava') {
|
||||
dependsOn checkUpperBoundDeps
|
||||
}
|
||||
}
|
||||
|
||||
plugins.withId("me.champeau.gradle.jmh") {
|
||||
dependencies {
|
||||
jmh 'org.openjdk.jmh:jmh-core:1.19',
|
||||
|
@ -582,3 +514,56 @@ subprojects {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DepAndParents {
|
||||
DependencyResult dep
|
||||
List<String> parents
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that Maven would select the same versions as Gradle selected.
|
||||
* This is essentially the same as if we used Maven Enforcer's
|
||||
* requireUpperBoundDeps for our artifacts.
|
||||
*/
|
||||
def requireUpperBoundDepsMatch(Configuration conf, Project project) {
|
||||
// artifact name => version
|
||||
Map<String,String> golden = conf.resolvedConfiguration.resolvedArtifacts.collectEntries {
|
||||
ResolvedArtifact it ->
|
||||
ModuleVersionIdentifier id = it.moduleVersion.id
|
||||
[id.group + ":" + id.name, id.version]
|
||||
}
|
||||
// Breadth-first search like Maven for dependency resolution
|
||||
Queue<DepAndParents> queue = new ArrayDeque<>()
|
||||
conf.incoming.resolutionResult.root.dependencies.each {
|
||||
queue.add(new DepAndParents(dep: it, parents: [project.displayName]))
|
||||
}
|
||||
Set<String> found = new HashSet<>()
|
||||
while (!queue.isEmpty()) {
|
||||
DepAndParents depAndParents = queue.remove()
|
||||
ResolvedDependencyResult result = (ResolvedDependencyResult) depAndParents.dep
|
||||
ModuleVersionIdentifier id = result.selected.moduleVersion
|
||||
String artifact = id.group + ":" + id.name
|
||||
if (found.contains(artifact))
|
||||
continue
|
||||
found.add(artifact)
|
||||
String version
|
||||
if (result.requested instanceof ProjectComponentSelector) {
|
||||
ProjectComponentSelector selector = (ProjectComponentSelector) result.requested
|
||||
version = project.findProject(selector.projectPath).version
|
||||
} else {
|
||||
version = ((ModuleComponentSelector) result.requested).version
|
||||
}
|
||||
String goldenVersion = golden[artifact]
|
||||
if (goldenVersion != version && "[$goldenVersion]" != version) {
|
||||
throw new RuntimeException(
|
||||
"Maven version skew: $artifact ($version != $goldenVersion) "
|
||||
+ "Bad version dependency path: " + depAndParents.parents
|
||||
+ " Run './gradlew $project.path:dependencies --configuration $conf.name' "
|
||||
+ "to diagnose")
|
||||
}
|
||||
result.selected.dependencies.each {
|
||||
queue.add(new DepAndParents(
|
||||
dep: it, parents: depAndParents.parents + [artifact + ":" + version]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,6 @@ export LDFLAGS=-L/tmp/protobuf/lib
|
|||
export CXXFLAGS="-I/tmp/protobuf/include"
|
||||
|
||||
./gradlew clean $GRADLE_FLAGS
|
||||
# Ensure dependency convergence
|
||||
./gradlew :grpc-all:dependencies $GRADLE_FLAGS
|
||||
|
||||
if [[ -z "${SKIP_TESTS:-}" ]]; then
|
||||
# Ensure all *.proto changes include *.java generated code
|
||||
|
|
|
@ -9,9 +9,9 @@ evaluationDependsOn(project(':grpc-api').path)
|
|||
|
||||
dependencies {
|
||||
api project(':grpc-api')
|
||||
guavaDependency 'implementation'
|
||||
censusApiDependency 'implementation'
|
||||
censusGrpcMetricDependency 'implementation'
|
||||
implementation libraries.guava,
|
||||
libraries.opencensus_api,
|
||||
libraries.opencensus_contrib_grpc_metrics
|
||||
|
||||
testImplementation project(':grpc-api').sourceSets.test.output,
|
||||
project(':grpc-context').sourceSets.test.output,
|
||||
|
|
|
@ -27,9 +27,9 @@ dependencies {
|
|||
implementation libraries.gson,
|
||||
libraries.android_annotations,
|
||||
libraries.animalsniffer_annotations,
|
||||
libraries.errorprone
|
||||
guavaDependency 'implementation'
|
||||
perfmarkDependency 'implementation'
|
||||
libraries.errorprone,
|
||||
libraries.guava,
|
||||
libraries.perfmark
|
||||
testImplementation project(':grpc-context').sourceSets.test.output,
|
||||
project(':grpc-api').sourceSets.test.output,
|
||||
project(':grpc-testing'),
|
||||
|
|
|
@ -35,7 +35,7 @@ android {
|
|||
dependencies {
|
||||
api project(':grpc-core'),
|
||||
libraries.cronet_api
|
||||
guavaDependency 'implementation'
|
||||
implementation libraries.guava
|
||||
testImplementation project(':grpc-testing')
|
||||
|
||||
testImplementation libraries.cronet_embedded
|
||||
|
|
|
@ -49,11 +49,6 @@
|
|||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java-util</artifactId>
|
||||
<version>${protobuf.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>annotations-api</artifactId>
|
||||
|
|
|
@ -14,13 +14,9 @@ dependencies {
|
|||
implementation project(':grpc-core'),
|
||||
project(':grpc-protobuf'),
|
||||
project(':grpc-stub'),
|
||||
libraries.protobuf
|
||||
implementation (libraries.protobuf_util) {
|
||||
// prefer our own versions instead of protobuf-util's dependency
|
||||
exclude group: 'com.google.guava', module: 'guava'
|
||||
exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
|
||||
}
|
||||
guavaDependency 'implementation'
|
||||
libraries.protobuf,
|
||||
libraries.protobuf_util,
|
||||
libraries.guava
|
||||
runtimeOnly libraries.errorprone
|
||||
compileOnly libraries.javax_annotation
|
||||
testImplementation libraries.truth,
|
||||
|
|
|
@ -28,9 +28,9 @@ dependencies {
|
|||
project(':grpc-testing'),
|
||||
project(path: ':grpc-xds', configuration: 'shadow'),
|
||||
libraries.junit,
|
||||
libraries.truth
|
||||
censusGrpcMetricDependency 'implementation'
|
||||
googleOauth2Dependency 'implementation'
|
||||
libraries.truth,
|
||||
libraries.opencensus_contrib_grpc_metrics,
|
||||
libraries.google_auth_oauth2_http
|
||||
compileOnly libraries.javax_annotation
|
||||
// TODO(sergiitk): replace with com.google.cloud:google-cloud-logging
|
||||
// Used instead of google-cloud-logging because it's failing
|
||||
|
|
|
@ -18,9 +18,10 @@ evaluationDependsOn(project(':grpc-core').path)
|
|||
dependencies {
|
||||
api project(':grpc-core'),
|
||||
libraries.netty
|
||||
implementation libraries.netty_proxy_handler
|
||||
guavaDependency 'implementation'
|
||||
perfmarkDependency 'implementation'
|
||||
implementation libraries.netty_proxy_handler,
|
||||
libraries.guava,
|
||||
libraries.errorprone,
|
||||
libraries.perfmark
|
||||
|
||||
// Tests depend on base class defined by core module.
|
||||
testImplementation project(':grpc-core').sourceSets.test.output,
|
||||
|
|
|
@ -11,14 +11,11 @@ description = "gRPC: OkHttp"
|
|||
evaluationDependsOn(project(':grpc-core').path)
|
||||
|
||||
dependencies {
|
||||
api project(':grpc-core')
|
||||
api (libraries.okhttp) {
|
||||
// prefer our own versions instead of okhttp's dependency
|
||||
exclude group: 'com.squareup.okio', module: 'okio'
|
||||
}
|
||||
implementation libraries.okio
|
||||
guavaDependency 'implementation'
|
||||
perfmarkDependency 'implementation'
|
||||
api project(':grpc-core'),
|
||||
libraries.okhttp
|
||||
implementation libraries.okio,
|
||||
libraries.guava,
|
||||
libraries.perfmark
|
||||
// Tests depend on base class defined by core module.
|
||||
testImplementation project(':grpc-core').sourceSets.test.output,
|
||||
project(':grpc-api').sourceSets.test.output,
|
||||
|
|
|
@ -12,8 +12,8 @@ description = 'gRPC: Protobuf Lite'
|
|||
dependencies {
|
||||
api project(':grpc-api'),
|
||||
libraries.protobuf_lite
|
||||
implementation libraries.jsr305
|
||||
guavaDependency 'implementation'
|
||||
implementation libraries.jsr305,
|
||||
libraries.guava
|
||||
|
||||
testImplementation project(':grpc-core')
|
||||
|
||||
|
|
|
@ -13,14 +13,12 @@ dependencies {
|
|||
api project(':grpc-api'),
|
||||
libraries.jsr305,
|
||||
libraries.protobuf
|
||||
guavaDependency 'implementation'
|
||||
implementation libraries.guava
|
||||
|
||||
api (libraries.google_api_protos) {
|
||||
// 'com.google.api:api-common' transitively depends on auto-value, which breaks our
|
||||
// annotations.
|
||||
exclude group: 'com.google.api', module: 'api-common'
|
||||
// Prefer our more up-to-date protobuf over 3.2.0
|
||||
exclude group: 'com.google.protobuf', module: 'protobuf-java'
|
||||
}
|
||||
|
||||
api (project(':grpc-protobuf-lite')) {
|
||||
|
|
|
@ -13,8 +13,8 @@ evaluationDependsOn(project(':grpc-core').path)
|
|||
dependencies {
|
||||
implementation project(':grpc-core'),
|
||||
project(':grpc-protobuf'),
|
||||
project(':grpc-stub')
|
||||
guavaDependency 'implementation'
|
||||
project(':grpc-stub'),
|
||||
libraries.guava
|
||||
compileOnly libraries.javax_annotation
|
||||
testImplementation libraries.truth,
|
||||
project(':grpc-grpclb'),
|
||||
|
|
|
@ -22,12 +22,8 @@ dependencies {
|
|||
api project(':grpc-protobuf'),
|
||||
project(':grpc-stub'),
|
||||
project(':grpc-core')
|
||||
implementation (libraries.protobuf_util) {
|
||||
// prefer our own versions instead of protobuf-util's dependency
|
||||
exclude group: 'com.google.guava', module: 'guava'
|
||||
exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
|
||||
}
|
||||
guavaDependency 'implementation'
|
||||
implementation libraries.protobuf_util,
|
||||
libraries.guava
|
||||
runtimeOnly libraries.errorprone
|
||||
|
||||
compileOnly libraries.javax_annotation
|
||||
|
|
|
@ -8,8 +8,8 @@ plugins {
|
|||
|
||||
description = "gRPC: Stub"
|
||||
dependencies {
|
||||
api project(':grpc-api')
|
||||
guavaDependency 'api'
|
||||
api project(':grpc-api'),
|
||||
libraries.guava
|
||||
testImplementation libraries.truth,
|
||||
project(':grpc-testing')
|
||||
signature "org.codehaus.mojo.signature:java17:1.0@signature"
|
||||
|
|
|
@ -13,8 +13,8 @@ dependencies {
|
|||
api project(':grpc-core'),
|
||||
project(':grpc-stub'),
|
||||
libraries.junit
|
||||
|
||||
censusApiDependency 'implementation'
|
||||
implementation libraries.opencensus_api
|
||||
runtimeOnly project(":grpc-context") // Pull in newer version than census-api
|
||||
|
||||
testImplementation (libraries.mockito) {
|
||||
// prefer our own versions instead of mockito's dependency
|
||||
|
|
|
@ -36,21 +36,11 @@ dependencies {
|
|||
libraries.gson,
|
||||
libraries.re2j,
|
||||
libraries.bouncycastle,
|
||||
libraries.autovalue_annotation
|
||||
libraries.autovalue_annotation,
|
||||
libraries.opencensus_proto,
|
||||
libraries.protobuf_util
|
||||
def nettyDependency = implementation project(':grpc-netty')
|
||||
|
||||
implementation (libraries.opencensus_proto) {
|
||||
// prefer our own versions instead of opencensus_proto's
|
||||
exclude group: 'com.google.protobuf', module: 'protobuf-java'
|
||||
exclude group: 'io.grpc', module: 'grpc-protobuf'
|
||||
exclude group: 'io.grpc', module: 'grpc-stub'
|
||||
}
|
||||
implementation (libraries.protobuf_util) {
|
||||
// prefer our own versions instead of protobuf-util's dependency
|
||||
exclude group: 'com.google.guava', module: 'guava'
|
||||
exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
|
||||
}
|
||||
|
||||
testImplementation project(':grpc-core').sourceSets.test.output
|
||||
|
||||
annotationProcessor libraries.autovalue
|
||||
|
|
Loading…
Reference in New Issue