-
Notifications
You must be signed in to change notification settings - Fork 201
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
More flexible reports for dependencies coming from BOMs #868
Comments
I don't think this information is provided in the gradle apis. If I understand correctly, it is internally modeled as a strictly dependency constraint. We'd have to see if this dependency was also listed in the configuration's getAllDependencyConstraints to guess that it was a BOM that might reported on differently. However, since we wouldn't know that, it could just as easily be your own constraints to avoid a version with a CVE, etc. Since builds vary quite a bit and not all of the information is available in the APIs, I find it slightly better to workaround in the build instead of trying to bake assumptions into this plugin. Then you have a few options for how you might coerce this plugin to report on the updates. One approach is to simply apply a resolution strategy to force the version. This is the easiest even though it is a little surprising when someone forgets about this configuration. Lets say you use version catalogs with an tasks.named<DependencyUpdatesTask>("dependencyUpdates").configure {
resolutionStrategy {
libs.bundles.enforcedPlatforms.get().forEach { library ->
force(library)
}
}
} The other approach is to rewrite the report before it is printed. import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
import com.github.benmanes.gradle.versions.reporter.PlainTextReporter
tasks.withType<DependencyUpdatesTask> {
outputFormatter {
val reporter = PlainTextReporter(project, revision, gradleReleaseChannel)
libs.bundles.enforcedPlatforms.get().forEach { library ->
exceeded.dependencies.removeAll { dependency ->
"${dependency.group}:${dependency.name}" == "${library.module}"
}
}
reporter.write(System.out, this)
}
} In both cases you would want to centralize your dependency definitions so that you can work with them programmatically. This tends to be a nice build cleanup in general and now idiomatic with version catalogs. You'll still need to opt-in the dependencies to ignore, but it will be very clear the next time you revisit the plugin's configuration what your customizations were and can easily add or remove as you see fit. |
@ben-manes Thank you very much for your fast reply! You understood me correctly. The idea is to prevent dependencies defined in a Your suggestion sounds like a possible solution, but from what I understand I should be defining the |
I'm not really sure the difference between your question options. I can show you what I did in Caffeine to apply constraints to ensure transitives with CVEs were upgraded for security analyzers. [bundles]
constraints = ["bcel", "bouncycastle-jdk18on", "commons-compress", "commons-text", "h2",
"httpclient", "guava", "jcommander", "jgit", "jsoup", "protobuf", "snakeyaml" ] dependencies {
libs.bundles.constraints.get().forEach { library ->
constraints.add("implementation", library.module.toString())
.version { require(library.version!!) }
}
} My examples adapted this to your situation. I defined the bundle so that I could group the dependencies and programmatically apply them. I could do it one-by-one, as I did for my report's individual forces, but with only a few (due to jdk compatibility reasons) I didn't generalize it there. Does those details help? |
re-reading and I see what you mean. You would want force the platform BOM itself instead of rewriting the report where you would need to know the individual dependencies and that would certainly be painful. You would need to somehow do this within the resolution strategy to apply the
|
Yeah, the idea is to avoid reports that suggest updating I am not sure your suggestion makes sense to me. The
I was thinking perhaps I could get the |
Ahh.. I just realized the
|
hmm, yeah this one is tricky. I don't know how using Gradle's apis one can do all of this. You can get the pom from an ArtifactResolutionQuery (example), but that full evaluation is a lot of messy code. I think that might be the only way though... When we copy a configuration we clear the dependencies and rewrite them with a dynamic version, |
Here is a proof-of-concept that works for you to extend further. It resolves all of the BOM dependencies and rejects any later version found. It is certainly a bit hacky but should be enough for you to play with until you are happy about the code quality. plugins {
id "com.github.ben-manes.versions" version "0.51.0"
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.code.gson:gson:2.10.1")
}
tasks.named("dependencyUpdates").configure {
def resolved = []
doFirst {
resolveBom("com.google.cloud", "libraries-bom", "26.40.0", resolved)
}
resolutionStrategy {
componentSelection {
all {
if (resolved.contains("${candidate.group}:${candidate.module}")
&& (candidate.version != currentVersion)) {
reject('Bom dependency')
}
}
}
}
}
def resolveBom(def group, def name, def version, def accumulator) {
def resolutionResult =
project.dependencies
.createArtifactResolutionQuery()
.forModule(group, name, version)
.withArtifacts(MavenModule, MavenPomArtifact)
.execute()
for (def result : resolutionResult.resolvedComponents) {
for (def artifact : result.getArtifacts(MavenPomArtifact)) {
if (artifact instanceof ResolvedArtifactResult) {
def file = artifact.file
def pom = new XmlSlurper(/* validating */ false, /* namespaceAware */ false).parse(file)
def dependencies = pom.dependencyManagement.dependencies.dependency
dependencies.each {
def coordinate = "${it.groupId.text()}:${it.artifactId.text()}"
if (accumulator.add(coordinate)) {
if ((it.scope.text() == 'import') || (it.type.text() == 'pom')) {
resolveBom(it.groupId.text(), it.artifactId.text(), it.version.text(), accumulator)
}
}
}
}
}
}
} |
Feature request
We'd like to suggest adding a flag that would stop showing dependencies in reports for dependencies that are pulled in via a
BOM
.The flag would probably need to have three modes:
default
- print the report as-is.silent
- don't show anydependency
update reports that have been pulled in from a BOM.warn
- print a one-liner saying `heyThe different modes would make the reports act slightly differently:
default
mode the end report would be as it is now:silent
mode would remove the dependency from the report.warn
could output something like this:A bit more context
We have multiple projects that enforce
bom
dependencies. Here's an example:When we run
./gradlew dependencyUpdates
the report will say there's a newercom.google.code.gson:gson
version:On its own the report is absolutely correct, but kind of lacks some flexibility and additional context.
Someone could easily be confused and decide to define
implementation("com.google.code.gson:gson:2.11.0")
which won't work, because the version2.10.1
is enforced via theenforcedPlatform
.Our case would fall under the
silent
mode if there were a flag.The text was updated successfully, but these errors were encountered: