-
Notifications
You must be signed in to change notification settings - Fork 466
Gradle dependency management refactoring #6139
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
base: main
Are you sure you want to change the base?
Conversation
- Refactored updateDependency() to accept GradleDependency parameter - Added getConfigurationName() method to GradleDependency trait - Fixed platform dependency handling in getPlatformDependency() - Updated scanner to use trait's getConfigurationName() method - Added varargs support attempt (not working yet) Current status: 71/75 tests passing (94.7%) Failing tests: - varargsDependency - leaveConstraintsAlone - mapNotationKStringTemplateInterpolation (2 variants)
- Added scanVarargsDependencies() to properly scan all literal dependencies in varargs calls - Added updateVarargsDependencies() to handle updating multiple dependencies in one call - The GradleDependency trait only processes first argument, so varargs need special handling - Varargs test now passes, but 3 other tests are failing and need investigation
- Created GradleMultiDependency trait to represent multiple dependencies in a single invocation - Uses synthetic J.MethodInvocation wrappers for each dependency - Provides map() method for clean functional transformation of dependencies - Refactored UpgradeDependencyVersion to use the new trait - Removed ad-hoc varargs handling code in favor of trait-based approach - Varargs test still passes, maintaining same 3 unrelated failing tests
- GradleMultiDependency now tracks groupId/artifactId filters from its Matcher - Added map(DependencyMatcher, mapper) method for explicit filtering - The trait only transforms dependencies that match the configured filters - This ensures selective updates when multiple dependencies are in one invocation - Added comprehensive tests to verify filtering behavior - Prevents unintended changes to non-matching dependencies in varargs
- Add support for K.StringTemplate in map notation (GradleDependency.getVersionVariable) Fixes mapNotationKStringTemplateInterpolation test - Skip upgrading dependencies without versions unless they are platform dependencies Prevents upgrading constraint-governed dependencies Fixes leaveConstraintsAlone test All 75 UpgradeDependencyVersionTest tests passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove redundant regex check in UpgradeDependencyVersion scanning phase GradleDependency.getVersionVariable() already returns null for literal versions, so checking !declaredVersion.matches("^[\\d\\.].*") was unnecessary - Clean up scanDependency to use trait methods directly (getGroupId/getArtifactId) instead of getDeclaredGroupId/getDeclaredArtifactId - Simplify updateDependency to check declaredVersion == null instead of checking isPlatform() for constraint handling All 75 UpgradeDependencyVersionTest tests still passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…andler. Incidentally resolves an OOM I was getting running locally due to ClasspathScanningLoader. There has to be something we can do to not have classgraph use all the memory.
cc760b3
to
069755b
Compare
rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyArtifactId.java
Outdated
Show resolved
Hide resolved
rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyGroupId.java
Outdated
Show resolved
Hide resolved
J.MethodInvocation m = super.visitMethodInvocation(method, ctx); | ||
|
||
Optional<GradleDependency> maybeGradleDependency = new GradleDependency.Matcher() | ||
m = GradleMultiDependency.matcher() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m = GradleMultiDependency.matcher() | |
return GradleMultiDependency.matcher() |
import java.util.Optional; | ||
import java.util.stream.Collectors; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import java.util.Optional; | |
import java.util.stream.Collectors; | |
import java.util.Optional; |
@Nullable | ||
private static String extractPropertyNameFromMethodInvocation(J.MethodInvocation mi) { | ||
if (mi.getSimpleName().equals("property") || mi.getSimpleName().equals("findProperty")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Nullable | |
private static String extractPropertyNameFromMethodInvocation(J.MethodInvocation mi) { | |
if (mi.getSimpleName().equals("property") || mi.getSimpleName().equals("findProperty")) { | |
private static @Nullable String extractPropertyNameFromMethodInvocation(J.MethodInvocation mi) { | |
if ("property".equals(mi.getSimpleName()) || "findProperty".equals(mi.getSimpleName())) { |
rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradleMultiDependency.java
Outdated
Show resolved
Hide resolved
rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradleMultiDependency.java
Outdated
Show resolved
Hide resolved
rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradleMultiDependency.java
Outdated
Show resolved
Hide resolved
) | ||
); | ||
} | ||
} No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
} |
rewrite-maven/src/test/java/org/openrewrite/maven/tree/DependencyTest.java
Outdated
Show resolved
Hide resolved
* Helper method to extract a string value from various expression types. | ||
* Handles literals, identifiers, field access, method invocations, and GStrings. | ||
*/ | ||
private @Nullable String extractValueAsString(Expression value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little worried about the prints contained in here for a couple of reasons:
- Sustainability/Incorrect results
- If a marker exists on one of these elements from a previous recipe, then the marker information will end up being printed here
GradleDependencyConfiguration gdc = getConfiguration(gradleProject, methodInvocation); | ||
if (gdc == null && !(DEPENDENCY_DSL_MATCHER.matches(methodInvocation) && !"project".equals(methodInvocation.getSimpleName()))) { | ||
return null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
callout: We're already performing this same check within isDependencyDeclaration
above.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
J.MethodInvocation m = super.visitMethodInvocation(method, ctx); | ||
|
||
Optional<GradleDependency> maybeGradleDependency = new GradleDependency.Matcher() | ||
m = GradleMultiDependency.matcher() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
m = GradleMultiDependency.matcher() | |
return GradleMultiDependency.matcher() |
import java.util.Optional; | ||
import java.util.stream.Collectors; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import java.util.Optional; | |
import java.util.stream.Collectors; | |
import java.util.Optional; |
@Nullable | ||
private static String extractPropertyNameFromMethodInvocation(J.MethodInvocation mi) { | ||
if (mi.getSimpleName().equals("property") || mi.getSimpleName().equals("findProperty")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Nullable | |
private static String extractPropertyNameFromMethodInvocation(J.MethodInvocation mi) { | |
if (mi.getSimpleName().equals("property") || mi.getSimpleName().equals("findProperty")) { | |
private static @Nullable String extractPropertyNameFromMethodInvocation(J.MethodInvocation mi) { | |
if ("property".equals(mi.getSimpleName()) || "findProperty".equals(mi.getSimpleName())) { |
@Nullable | ||
private static String extractPropertyNameFromGBinary(G.Binary binary) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Nullable | |
private static String extractPropertyNameFromGBinary(G.Binary binary) { | |
private static @Nullable String extractPropertyNameFromGBinary(G.Binary binary) { |
((G.MapLiteral) firstArg).getElements() : m.getArguments().stream() | ||
.filter(G.MapEntry.class::isInstance) | ||
.map(G.MapEntry.class::cast) | ||
.collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.collect(Collectors.toList()); | |
.collect(toList()); |
((G.MapLiteral) firstArg).getElements() : m.getArguments().stream() | ||
.filter(G.MapEntry.class::isInstance) | ||
.map(G.MapEntry.class::cast) | ||
.collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.collect(Collectors.toList()); | |
.collect(toList()); |
m.getArguments().stream() | ||
.filter(G.MapEntry.class::isInstance) | ||
.map(G.MapEntry.class::cast) | ||
.collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.collect(Collectors.toList()); | |
.collect(toList()); |
) | ||
); | ||
} | ||
} No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
} |
Gradle dependency declarations can take many forms. To list a subset of the variations:
The logic to handle these different syntax is scattered around the various dependency management recipes, which each of them covering incompletely-overlapping subsets.
This PR centralizes this syntactical knowledge into the
GradleDependency
trait and theGradleMultiDependency
trait.GradleDependency
should now be a one-stop-shop for reading and refactoring dependency declarations of all kinds.GradleMultiDependency
exists only to abstract away the groovy-specific varargs version of a dependency declaration. This is necessaryNot every recipe has been updated to fully take advantage of this, but this PR is sprawling enough as-is.
Other enhancements include:
StringUtils.matchesGlob()
no longer requires anull
check to get the most commonly desired behaviororg.openrewrite.gradle.internal.Dependency
and its parser separate fromorg.openrewrite.maven.Dependency
RemoveRedundantDependencyVersion
andUpgradeDependencyVersion