Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve dependency constraints. #351

Merged
merged 3 commits into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions examples/groovy/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ configurations {
bom
upToDate
exceedLatest
platform
upgradesFound
upgradesFound2
unresolvable
Expand Down Expand Up @@ -76,4 +77,14 @@ dependencies {
'com.github.ben-manes:unresolvable2:1.0'
unresolvable2 'com.github.ben-manes:unresolvable:1.0',
'com.github.ben-manes:unresolvable2:1.0'

platform 'com.linecorp.armeria:armeria',
'io.zipkin.brave:brave'
// Common usage would be to separate this into a project that uses the `java-platform` plugin to
// share constraints among several projects.
constraints {
platform 'com.linecorp.armeria:armeria:0.90.0',
'io.zipkin.brave:brave:5.7.0'

}
}
9 changes: 9 additions & 0 deletions examples/kotlin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ configurations {
register("bom")
register("upToDate")
register("exceedLatest")
register("platform")
register("upgradesFound")
register("upgradesFound2")
register("unresolvable")
Expand Down Expand Up @@ -74,4 +75,12 @@ dependencies {
"unresolvable"("com.github.ben-manes:unresolvable2:1.0")
"unresolvable2"("com.github.ben-manes:unresolvable:1.0")
"unresolvable2"("com.github.ben-manes:unresolvable2:1.0")
"platform"("com.linecorp.armeria:armeria")
"platform"("io.zipkin.brave:brave")
// Common usage would be to separate this into a project that uses the `java-platform` plugin to
// share constraints among several projects.
constraints {
"platform"("com.linecorp.armeria:armeria:0.90.0")
"platform"("io.zipkin.brave:brave:5.7.0")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.github.benmanes.gradle.versions.updates
import groovy.transform.EqualsAndHashCode
import groovy.transform.TypeChecked
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.DependencyConstraint
import org.gradle.api.artifacts.ModuleVersionIdentifier
import org.gradle.api.artifacts.ModuleVersionSelector
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
Expand Down Expand Up @@ -61,6 +62,10 @@ class Coordinate implements Comparable<Coordinate> {
return new Coordinate(dependency.group, dependency.name, dependency.version)
}

static Coordinate from(DependencyConstraint dependency) {
return new Coordinate(dependency.group, dependency.name, dependency.version)
}

static Coordinate from(ModuleVersionIdentifier identifier) {
return new Coordinate(identifier.group, identifier.name, identifier.version)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.gradle.api.artifacts.ComponentMetadata
import org.gradle.api.artifacts.ComponentSelection
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.DependencyConstraint
import org.gradle.api.artifacts.ExternalDependency
import org.gradle.api.artifacts.LenientConfiguration
import org.gradle.api.artifacts.ModuleVersionIdentifier
Expand Down Expand Up @@ -117,6 +118,15 @@ class Resolver {
createQueryDependency(dependency, revision)
}

// Common use case for dependency constraints is a java-platform BOM project.
try {
configuration.dependencyConstraints.each { dependency ->
latest.add(createQueryDependency(dependency, revision))
}
} catch (MissingPropertyException e) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other cases we've guarded using metaClass.respondsTo("..."). Which do you consider preferable?

// Skip if constraints not supported
}

Configuration copy = configuration.copyRecursive().setTransitive(false)
// https://github.com/ben-manes/gradle-versions-plugin/issues/127
if (copy.metaClass.respondsTo(copy, "setCanBeResolved", Boolean)) {
Expand Down Expand Up @@ -149,6 +159,19 @@ class Resolver {
}
}

/** Returns a variant of the provided dependency used for querying the latest version. */
@TypeChecked(SKIP)
private Dependency createQueryDependency(DependencyConstraint dependency, String revision) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its probably not simpler to combine this with the other createQueryDependency, though the duplication could lead to mistakes of fixing one instead of both.

String versionQuery = useSelectionRules ? '+' : "latest.${revision}"

// If no version was specified then use 'none' to pass it through.
String version = dependency.version == null ? 'none' : versionQuery

return project.dependencies.create("${dependency.group}:${dependency.name}:${version}") {
transitive = false
}
}

/** Adds a revision filter by rejecting candidates using a component selection rule. */
@TypeChecked(SKIP)
private void addRevisionFilter(Configuration configuration, String revision) {
Expand Down Expand Up @@ -184,12 +207,11 @@ class Resolver {

/** Returns the coordinates for the current (declared) dependency versions. */
private Map<Coordinate.Key, Coordinate> getCurrentCoordinates(Configuration configuration) {
Map<Coordinate.Key, Coordinate> declared = configuration.dependencies.findAll { dependency ->
dependency instanceof ExternalDependency
}.collectEntries {
Coordinate coordinate = Coordinate.from(it)
return [coordinate.key, coordinate]
}
Map<Coordinate.Key, Coordinate> declared =
getResolvableDependencies(configuration).collectEntries {
return [it.key, it]
}

if (declared.isEmpty()) {
return Collections.emptyMap()
}
Expand Down Expand Up @@ -217,6 +239,15 @@ class Resolver {
coordinates.put(coordinate.key, declared.get(coordinate.key))
}

try {
for (DependencyConstraint constraint : copy.dependencyConstraints) {
Coordinate coordinate = Coordinate.from(constraint)
coordinates.put(coordinate.key, declared.get(coordinate.key))
}
} catch (MissingPropertyException e) {
// Skip if constraints not supported
}

// Ignore undeclared (hidden) dependencies that appear when resolving a configuration
coordinates.keySet().retainAll(declared.keySet())

Expand Down Expand Up @@ -333,6 +364,24 @@ class Resolver {
return null
}

private static List<Coordinate> getResolvableDependencies(Configuration configuration) {
List<Coordinate> coordinates = configuration.dependencies.findAll { dependency ->
dependency instanceof ExternalDependency
}.collect { dependency ->
Coordinate.from(dependency)
}

try {
configuration.dependencyConstraints.each {
coordinates.add(Coordinate.from(it))
}
} catch (MissingPropertyException e) {
// Skip
}

return coordinates
}

private static final class ProjectUrl {
boolean isResolved
String url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,40 @@ final class JavaLibrarySpec extends Specification {
result.output.contains('com.google.inject:guice [2.0 -> 3.1]')
result.task(':dependencyUpdates').outcome == SUCCESS
}

def "Show updates for an api dependency constraint in a java-library project"() {
given:
def mavenRepoUrl = getClass().getResource('/maven/').toURI()
buildFile = testProjectDir.newFile('build.gradle')
buildFile <<
"""
plugins {
id 'java-library'
id 'com.github.ben-manes.versions'
}

repositories {
maven {
url '${mavenRepoUrl}'
}
}

dependencies {
constraints {
api 'com.google.inject:guice:2.0'
}
}
""".stripIndent()

when:
def result = GradleRunner.create()
.withProjectDir(testProjectDir.root)
.withArguments('dependencyUpdates')
.withPluginClasspath()
.build()

then:
result.output.contains('com.google.inject:guice [2.0 -> 3.1]')
result.task(':dependencyUpdates').outcome == SUCCESS
}
}