Recipe quality triage: behaviour fixes and design questions (A1–E4)
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 25/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 活跃
- 技术栈
- java
- 领域
- backend, build-system
调研方向
Choose one item from section B–E and search the named recipe and test paths under src/main/java/org/openrewrite/java/dependencies/ and src/test/java/org/openrewrite/java/dependencies/; the issue gives item-specific locations and reproduction details. Start with the matching probe or reproduction, then add a test for the selected behavior before changing it. Done means the test verifies correct expected output and the recipe no longer causes the described behavior; section A items require a maintainer decision before work starts.
由索引模型根据 Issue 内容生成。
描述
We triaged every recipe in this repo against the recipe review checklist we used for openrewrite/rewrite-spring#1201, openrewrite/rewrite-testing-frameworks#1211 and openrewrite/rewrite-migrate-java#1330. The mechanical fixes are tracked in #210. This issue tracks the rest: recipes that produce wrong output, miss common shapes, or need a design decision.
The wrappers here are used widely: other recipe modules reference ChangeDependency, AddDependency, UpgradeDependencyVersion and RemoveDependency about 1,600 times. A change in semantics therefore reaches far beyond this repo, which is why several items below are questions rather than fixes.
Each item is self-contained, so you can pick one up on its own or point an agent at it ("work on item B3 of this issue"). Please reference the item ID in your PR title or description. When you open the PR, tick the item's box and add the PR number after its title, e.g. (#1234). If the PR covers only some bullets, also add "Fixed in #1234." to those bullets. Untick the box if the PR is closed without merging.
How to pick up an item
- Line numbers are against
mainat74e6bdband may have drifted, so search by symbol if needed. - Paths are abbreviated:
M/=src/main/java/org/openrewrite/java/dependencies/T/=src/test/java/org/openrewrite/java/dependencies/- CSV =
src/main/resources/migrations.csv
- Status tags:
- PROBED means a throwaway test reproduced the behaviour; the snippet is included where one helps.
- CONFIRMED means the code path was traced but not run.
- SUSPECTED means it was inferred from reading. Write the probe test first. If it doesn't reproduce, close the item with a note.
- Tests resolve real POMs from Maven Central. A 429 from Central looks like "Recipe was expected to make a change but made no changes", so confirm a test passes on unmodified
mainbefore blaming the recipe. ThewithToolingApi()tests survive the rate limit if theirbuild.gradleusesmaven { url 'https://maven-central.storage-download.googleapis.com/maven2' }instead ofmavenCentral(). - When a recipe can't preserve the build's resolution, prefer bailing out (making no change) over guessing.
- Every fix comes with a test. Expected output must be correct, not just a record of today's behaviour.
- Items in A need a maintainer decision first. Comment on the issue before starting.
- Items marked quick win only make a recipe skip more or report better, so they need no decision.
Start here: the most harmful items
- B1–B4, B6:
RemoveRedundantDependenciesdeletes declarations the build still needs. All of these were probed. The causes are optional dependencies, deep exclusions, classifiers, version mediation andstrictlypins. - D1:
DependencyList(validateResolvable=true)validates the project's own coordinates instead of each dependency's. - C1:
RemoveDependencywithunlessUsingempties a rootsubprojects {}block that a subproject still uses. - E3:
RelocatedDependencyCheck(changeDependencies=true)jumps tolatest.release, across majors and javax→jakarta. It also invents coordinates that don't exist. - B5:
RemoveRedundantDependenciesdrops animplementationdependency that acompileOnlydependency provides. - D2:
DependencyListdrops Gradle subprojects that share group, name and version, and emits nothing on a second run of the same instance.
A. Design decisions (decide first)
-
A1 Map Maven scope and Gradle configuration consistently, and expose the delegates' missing options
Details
-
Today:
M/AddDependency:203-208mapsscopeto a Gradle configuration, but neverconfigurationto a Maven scope.M/DependencyInsight:78passesnullas the Gradle configuration.M/RemoveDependency:110-111,M/ExcludeDependency:92-98andM/FindDependency:70-73map neither way.- The search recipes behave the same way (see A3).
-
Effect:
- PROBED:
DependencyInsight(.., scope = "compile")marks a Gradle build that only hastestImplementation "com.google.guava:guava:29.0-jre". - CONFIRMED:
AddDependencywith onlyconfiguration: testImplementationadds a Maven dependency at the scope inferred fromonlyIfUsing, or compile. - CONFIRMED: a Maven-only
scopeonRemoveDependencyorExcludeDependencyapplies to every Gradle configuration, and the reverse.
- PROBED:
-
Delegate options not exposed (CONFIRMED):
- Gradle
onlyForConfigurations(M/UpgradeTransitiveDependencyVersion:169passesnull) - Maven
onlyDirectand GradleconfigurationinDependencyInsight(M/DependencyInsight:78-80);ModuleHasDependencygainedonlyDirectin #199 - Maven
typevs GradleextensioninM/AddDependency:209-221, which aren't mapped onto each other releasesOnly,onlyIfUsingandaddToRootPominUpgradeTransitiveDependencyVersion, which are silent no-ops on Gradle
- Gradle
-
Decide:
- Either translate both ways:
Scope.asGradleConfigurationNamefor declaring recipes, and resolvable classpaths forDependencyInsight(compile→compileClasspath,test→testRuntimeClasspath). - Or document
scopeas Maven-only everywhere.
Adding an option needs a new
@JsonCreatorconstructor that keeps the old arity, because of how many YAML recipes use these. - Either translate both ways:
-
-
A2
AddDependencybehaves differently on Maven and GradleDetails
- Transitives (PROBED):
AddDependency("com.google.guava", "failureaccess", "1.0.1", ..)on a project that hasguava:29.0-jreadds the dependency on Maven but not on Gradle. The Gradle delegate ignoresacceptTransitiveandfamilyPattern: it declares them but never reads them, and always callsremoveConfigurationsContainingTransitiveDependency. - No version (PROBED): Maven gets
latest.release(3.21.0), while Gradle getsimplementation "org.apache.commons:commons-lang3", which only resolves if a platform manages the version. Related: #182. - Multi-module (SUSPECTED): without
onlyIfUsing, Maven adds the dependency once to the parent in the repository. Gradle adds it to everybuild.gradle, including a plugin-less root script, whereimplementationdoesn't exist. - Decide:
- Either fix the Gradle delegate upstream in openrewrite/rewrite so it honours
acceptTransitive, passlatest.releaseunless a platform manages the dependency, and align the multi-module targeting. - Or document each difference and mark the affected options "For Maven only".
- Either fix the Gradle delegate upstream in openrewrite/rewrite so it honours
- Transitives (PROBED):
-
A3
ModuleHasDependency,RepositoryHasDependencyandDoesNotIncludeDependencyvs their core counterpartsDetails
-
Drift:
- Core
org.openrewrite.maven.search.ModuleHasDependencyandorg.openrewrite.gradle.search.ModuleHasDependencydo the same scan. They lackinvertMarking, the requested-dependency fallback (#179), and the marking of files without aJavaProject(#147). The core Gradle one does have aconfigurationoption. - Fixes keep landing here (#150, #174, #176, #179, #199) and not in core.
- Core
-
Parity (CONFIRMED):
M/search/ModuleHasDependency:62-68,143-167:scopeonly applies to Maven. On Gradle,scope=testmatchesimplementationdependencies, and there is noconfigurationoption.M/search/RepositoryHasDependency: noonlyDirectand noconfiguration.M/search/DoesNotIncludeDependency:75-80: dropsonlyDirect/scopefor Gradle andconfigurationfor Maven.
-
Decide:
- Either move
invertMarkingand the requested-dependency fallback into core and make these thin delegates. - Or declare these canonical and deprecate the core pair.
Either way, make the options symmetric (see A1). Related: openrewrite/rewrite#6468.
- Either move
-
-
A4 Version policy, chains and data source for
RelocatedDependencyCheck(#219)Details
- Depends on: the decisions behind E3 and E4, which together decide whether
changeDependencies=trueis safe to recommend. - Decide:
- Keep the old version when the target publishes it (a true relocation), and otherwise only mark; or keep
latest.release. - Keep the group-only fallback, verify its targets, or drop it.
- Fix the data upstream in oga-maven-plugin, or keep a local override layer that survives regeneration.
- Keep the old version when the target publishes it (a true relocation), and otherwise only mark; or keep
- Depends on: the decisions behind E3 and E4, which together decide whether
-
A5 Replace
internal/*with core'sorg.openrewrite.maven.tree.Version(#223)Details
-
Where:
M/internal/Version,VersionParserandStaticVersionComparator, copied from Gradle incdd48ed(2023).- Used only by
M/search/FindMinimumDependencyVersion:87,108-114,179-191andM/search/FindMinimumJUnitVersion:83,141-153.
-
Problem (PROBED): these classes order Maven versions differently from the resolver that core uses:
Comparison internalcore Version1.0.0-SP1vs1.0.0<>Hoxton.SR1vsHoxton.RELEASE<>5.3.0.RELEASEvs5.3.0<=1.0.0.Finalvs1.0.0<=2.0vs2.0.0<=StaticVersionComparatoralso returns0for different strings (1.1.1vs1-1-1), soacc.mergekeeps whichever one it sees first. -
Fix: use
new Version(a).compareTo(new Version(b)), and deleteinternal/andT/internal/StaticVersionComparatorTest. Because this changes which version counts as the minimum, check with downstream users of the two search recipes first.
-
-
A6
FindMinimumJUnitVersion: JUnit 6, and repository-wide answers (#224)Details
- Where:
M/search/FindMinimumJUnitVersion:51,109-110,138. - Problem (CONFIRMED):
junit-jupiter-api:6.xcounts as "JUnit 5", andvalid = {"4", "5"}can't express 6. The answer is computed for the whole repository, so one module still on JUnit 4 decides for all of them. - Decide: key the families on the major version (4/5/6) and allow
"6". Consider answering perJavaProject. Check how rewrite-testing-frameworks uses this before changing the semantics.
- Where:
B. RemoveRedundantDependencies removes declarations the build needs
This recipe deletes declarations, so a false positive changes the classpath. B1–B4 share a root cause: redundancy is decided by resolving the provider's POM in isolation. B4 proposes a design that fixes all four together. Prior art: openrewrite/rewrite#8235 and openrewrite/rewrite#8336, and #191, #194 and #195 here.
-
B1 Maven: the provider's
<optional>dependencies count as transitive (quick win)Details
- Where:
M/RemoveRedundantDependencies:158-166. The provider is resolved as a root, andResolvedPomonly drops optional dependencies at depth ≥ 1. The comment at:157is inaccurate for the same reason. - Problem (PROBED): with
commons-compress:1.26.0and an explicitorg.tukaani:xz:1.9,RemoveRedundantDependencies("org.apache.commons", "commons-compress")deletesxz.xzis optional in commons-compress, so it disappears from the classpath. - Fix: skip the provider's own optional dependencies when collecting, or adopt B4.
- Where:
-
B2 Maven: project exclusions are only applied to the provider's direct dependencies
Details
- Where:
M/RemoveRedundantDependencies:173-180,104,134. - Problem (PROBED): with
spring-boot-starter-json:3.2.0excludingjackson-core, and an explicitjackson-core:2.15.3, the recipe still deletesjackson-core. The exclusion is what makes the explicit declaration necessary.- SUSPECTED: wildcard exclusions only work as far as
getEffectiveExclusions()lists them, which mediation can prune (see the recipe's own comment at:194-196).
- SUSPECTED: wildcard exclusions only work as far as
- Fix: resolve through a synthetic root that carries the declared exclusions, or adopt B4.
- Where:
-
B3 Classifier and type are ignored (quick win)
Details
- Where:
M/RemoveRedundantDependencies:297-313(matches on GA and version only),:259-260,287-288(RemoveDependencyby GA). - Problem (PROBED):
jackson-core:2.17.0with classifiersourcesis deleted becausejackson-databindprovides the plain jar. The same applies totests/test-jarand native classifiers.- SUSPECTED: when the GA is declared both with and without a classifier, both declarations are removed.
- Fix: never treat a declaration with a classifier or a non-
jartype as redundant.
- Where:
-
B4 Removal can change the mediated version
Details
- Where:
M/RemoveRedundantDependencies:147-171,304-306. - Problem (PROBED): Maven picks the nearest version, and the first declared one wins at the same depth. Once the direct declaration is gone, an earlier sibling can win:
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-yaml</artifactId><version>2.15.0</version></dependency> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.17.0</version></dependency> <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.17.0</version></dependency> <!-- RemoveRedundantDependencies("com.fasterxml.jackson.core", "jackson-databind") deletes jackson-core: 2.17.0 → 2.15.0 --> - Fix (design): decide redundancy by re-resolving the project's own POM without the candidate. Remove the candidate only if its resolved GAV, scope, classifier and type stay the same in every scope. This replaces the provider-POM approach and its scope and exclusion bookkeeping, and fixes B1–B3 too.
- Where:
-
B5 Gradle: a
compileOnlyprovider makes animplementationdeclaration look redundantDetails
- Where:
M/RemoveRedundantDependencies:93-111,242-266:259-261:RemoveDependency(g, a, null, null, null)removes the dependency from every configuration.:344-357:getBroaderGradleScopesis a hard-coded table, and is missingcompileOnly,testCompileOnly,annotationProcessorand the*Classpathconfigurations.
- Problem (PROBED): with
compileOnly 'jackson-databind:2.17.0'andimplementation 'jackson-core:2.17.0', the recipe deletesjackson-core, which then disappears fromruntimeClasspath. These cases were probed and are fine:- a
testImplementationprovider with animplementationchild - a
runtimeOnlyprovider with animplementationchild - an
implementationprovider with anapichild
- a
- Fix: only remove a declaration when the provider is declared in the same configuration, or in one that it extends from. Use
GradleDependencyConfiguration.getExtendsFrom(), and pass the configuration toRemoveDependency.
- Where:
-
B6 Gradle: rich versions are removed (quick win)
Details
- Where:
M/RemoveRedundantDependencies:202-207.constrainsResolutiononly catches ranges,+andlatest.. - Problem (PROBED):
implementation('com.fasterxml.jackson.core:jackson-core') { version { strictly '2.17.0' } }is removed next tojackson-databind:2.17.0, which drops the pin.requested.getVersion()only carries the constraint when the strict version is itself a range.- SUSPECTED: the same applies to
!!,require/reject,force = trueandbecause.
- SUSPECTED: the same applies to
- Fix: keep any declaration that has a closure or
version {}block, a!!suffix, orforce. Read this from the LST via theGradleDependencytrait, because the marker can't tell.
- Where:
-
B7 Download failures are silent, and Maven Central is always added
Details
- Where:
M/RemoveRedundantDependencies:167-170,209-216. - Problem (CONFIRMED):
- A 429 or an unreachable private repository looks the same as "nothing redundant", in tests and in production.
withMavenCentraladds Central to every project, which is wrong for air-gapped builds without amirrorOf *mirror.
- Fix: report the failure through
ctx.getOnError()or aMarkup.warnon the build file. Use the project's effective repositories as they are, sinceMavenPomDownloaderalready applies the settings mirrors.
- Where:
-
B8 Gradle: the accumulator key and the source of metadata
Details
- Where:
M/RemoveRedundantDependencies:90,243key projects bygroup:name;:158-159resolves the provider's POM. - Problem (SUSPECTED):
:a:coreand:b:coreshare their transitives, the same issue as D2.- With Gradle Module Metadata (variants, capabilities, platforms, as Jackson publishes), the provider's POM is not what Gradle resolves.
- Fix: key by
GradleProject.getPath(). Longer term, read the provider's children from the marker's own resolved graph instead of re-resolving a POM.
- Where:
C. Wrapper and search recipe bugs
-
C1
RemoveDependencywithunlessUsingempties rootsubprojects {}blocks that a subproject usesDetails
- Where:
M/RemoveDependency:118-127. Only Maven got the descendant check,anyDescendantPreservesDependencyat:146-169(#183). - Problem (PROBED): the root declares
subprojects { dependencies { implementation "com.google.guava:guava:29.0-jre" } }, and the child usescom.google.common.math.IntMath. WithunlessUsing = "com.google.common..*", the root block is still emptied, because the root project doesn't use the type itself.- The same applies to
allprojects {}, convention plugins andapply from:scripts. - Build files without a
JavaProjectmarker are skipped silently (:120). That is safe, but undocumented.
rewriteRun( spec -> spec.beforeRecipe(withToolingApi()).parser(JavaParser.fromJavaVersion().classpath("guava")) .recipe(new RemoveDependency("com.google.guava", "guava", "com.google.common..*", null, null)), mavenProject("root", settingsGradle("rootProject.name = 'root'\ninclude 'child'"), buildGradle(""" subprojects { apply plugin: "java-library" repositories { mavenCentral() } dependencies { implementation "com.google.guava:guava:29.0-jre" } } """), mavenProject("child", srcMainJava(java("import com.google.common.math.IntMath; class A { boolean b() { return IntMath.isPrime(5); } }")), buildGradle(""))) ); // root dependencies {} is emptied - The same applies to
- Fix: treat a declaration in a cross-project block as in use when any project in the build uses the type. At minimum, bail out when the declaration sits in such a block.
- Where:
-
C2
RepositoryHasDependencyignores build files without aJavaProjectmarker (quick win)Details
- Where:
M/search/RepositoryHasDependency:93-99. - Problem (CONFIRMED): a repository-wide check doesn't need a module marker. Root aggregator POMs and some LST producers have no
JavaProjectmarker, so their dependencies never set the flag. - Fix: call
hasDependency(tree)without theJavaProjectgate.
- Where:
-
C3
FindMinimumDependencyVersion: whatversionfilters, which configurations are scanned, and duplicate rowsDetails
- Where:
M/search/FindMinimumDependencyVersion:89-93,110-115,136-140,153-175. - Problem:
- CONFIRMED (
:110-115):versionfilters the computed minimum, not the dependencies. With 1.0 in test and 2.5 in main,version=2.xfinds nothing, although the option promises "Match only dependencies with the specified version" (:57). - SUSPECTED (
:89-93,136-140): every Gradle configuration is scanned, includingcheckstyle,spotbugs,kotlinCompilerClasspathandannotationProcessor. A plugin's own Jackson can become "the oldest Jackson in use". - CONFIRMED (
:153-175):DependenciesInUsegets one row per scope and match. Maven compile dependencies therefore repeat underprovided,runtimeandtest.sourceSetis"unknown"forpom.xml, and probably forbuild.gradletoo.countis always1.- The marker lands on the whole build file rather than the declaration.
- CONFIRMED (
- Fix:
- Decide which
versionsemantics is meant, and align the code and the text. - Restrict Gradle to the
*CompileClasspathand*RuntimeClasspathconfigurations. - Deduplicate the rows per project, GAV and scope.
- Mark the declaration where there is one.
- Decide which
- Where:
-
C4
FindDuplicateClassesonly reports source sets that contain JavaDetails
- Where:
M/search/FindDuplicateClasses:66-68,75-79. - Problem (SUSPECTED):
- A source set with only Kotlin or Groovy sources is never reported, because
JavaVisitor.visitCompilationUnitisn't reached for aK.CompilationUnitor aG.CompilationUnit. - Two modules with the same
projectNameshare the deduplication key, so only one of them is reported.
- A source set with only Kotlin or Groovy sources is never reported, because
- Fix: use a
TreeVisitor<SourceFile>that readsJavaSourceSetfrom any source file, and key onJavaProjectplus the source set name.
- Where:
D. Reports and diagnostics
-
D1
DependencyList(validateResolvable=true)checks the project's own coordinatesDetails
- Where:
M/DependencyList:131-141(Gradle) and:166-182(Maven). Both branches calldownloadMetadata(new GroupArtifact(<project group>, <project artifact>), ..)instead of using the dependency's coordinates. - Problem (PROBED):
- A pom
com.test.notpublished:testthat depends onslf4j-api:2.0.9reportsslf4j-apias unresolvable:com.test.notpublished:test failed. Unable to download metadata. - Conversely, a missing dependency of a published project is reported as fine.
- The same false failures land in
MavenMetadataFailures. T/DependencyListTest:139-201only passes because its project and its dependency share coordinates (:177,184,192).- The Gradle branch passes
nullsettings, while the Maven branch merges the marker's settings with the context's.
- A pom
- Fix: download
dep.getGav()againstdep.getRepository()plus the project repositories, with the same settings handling on both sides. Deduplicate by GAV, becauseincludeTransitivemultiplies the requests. Change the test so the project and dependency coordinates differ. - Related: #187, which also notes that the metadata cache has no TTL. "Unavailable since the LST was produced" therefore only holds for a cold cache.
- Where:
-
D2
DependencyListdrops Gradle subprojects, and keeps state on the recipe instanceDetails
- Where:
M/DependencyList:78,97.seenGradleProjectsis atransientfield of a@Valuerecipe, keyed bygroup:name:version. - Problem (PROBED):
- With
include 'a:core', 'b:core'sharing a group and version, onlya/coregets rows. - Running the same instance twice, the second run emits no rows at all.
- SUSPECTED: wherever one instance is reused across repositories, later projects named
appwith anunspecifiedversion disappear.
- With
- Fix: key on the project path (
gradle.getPath()) and keep the set per run, as anExecutionContextmessage or the accumulator of aScanningRecipe. The field exists to deduplicate script plugins that share the build script's marker (:74-77), and that still needs to work.
- Where:
-
D3
DependencyListproduces no rows for builds without the standard JVM configurationsDetails
- Where:
M/DependencyList:99,220-231. - Problem (SUSPECTED):
scope()maps only tocompileClasspath,runtimeClasspathandtestRuntimeClasspath. Android (debugCompileClasspath), Kotlin Multiplatform (jvmCompileClasspath) andjava-platformprojects are skipped silently. MavenCompilealso includesprovided, which the option text doesn't say. - Decide: fall back to the variant configurations, add a
configurationoption, or document the limitation.
- Where:
-
D4
DependencyResolutionDiagnosticreports HTTP 200 for repositories that answered with an errorDetails
- Where:
M/DependencyResolutionDiagnostic:211-227. In core,MavenPomDownloader.normalizeRepositorytreats any server response (401, 403, 404, 5xx) as "reachable" without notifying the listener. - Problem (PROBED):
https://repo1.maven.org/this-path-does-not-existgetspingHttpCode=200. A repository that answers 401 for lack of credentials shows 200 too. The column promises "The HTTP response code returned by the repository". - Fix: probe the status through the
HttpSender(as #187 does), or leave the column empty when the code is unknown. Alternatively, ask core to expose the reachability status.
- Where:
-
D5
DependencyResolutionDiagnosticsays "unknown reason" for repositories that already failed in this run (quick win)Details
- Where:
M/DependencyResolutionDiagnostic:160-172, with the accumulator at:92-98. - Problem (PROBED): only
repositoryAccessFailedis overridden. Core callsrepositoryAccessFailedPreviouslywhen it has cached a failure for the repository, or when the endpoint is already unreachable.- Probe: with two repositories on the same dead host, one row gets
UnknownHostExceptionand the other "Repository unreachable for unknown reason". - The
HashSets make it random which of the two rows gets which message.
- Probe: with two repositories on the same dead host, one row gets
- Fix:
- Override
repositoryAccessFailedPreviously, keeping the first failure per URI. - Use
LinkedHashSets. - Drop the redundant
foundGradle(:93).
- Override
- Where:
-
D6
DependencyResolutionDiagnosticreads caches, although it promises current conditionsDetails
- Where: the description at
M/DependencyResolutionDiagnostic:55-56;recordat:139-202. - Problem:
- CONFIRMED from core's source:
normalizeRepositorycaches its results, and downloads return cached POMs, cached 404s included. With the CLI's shared POM cache, or after other dependency recipes in the same run, the columns can come from cache without any network access. - PROBED: the
file:local repository row reportsMavenDownloadingExceptionwhenever~/.m2doesn't havejackson-core:2.16.0. - There is no column for the GAV that was tried.
- CONFIRMED from core's source:
- Fix:
- Probe against a fresh
InMemoryMavenPomCache, or through the rawHttpSender. - Skip the resolution check for
file:repositories. - Add a GAV column.
- Soften the description.
- Probe against a fresh
- Related: #187.
- Where: the description at
-
D7
DependencyResolutionDiagnosticignores Kotlin DSL builds, and script plugins duplicate its rows (quick win)Details
- Where:
M/DependencyResolutionDiagnostic:247-268(aGroovyIsoVisitoronG.CompilationUnit) and:277(endsWith("build.gradle")). - Problem:
- PROBED: a
build.gradle.ktswithout aGradleProjectmarker gets no warning. - CONFIRMED:
GradleDependencyConfigurationErrorsis never populated for.ktsbuilds. - CONFIRMED: script plugins share the build script's marker, so they re-emit the same configuration-error rows.
- PROBED: a
- Fix: use a
TreeVisitoroverSourceFilewith anIsBuildGradle-style check that includes.kts, and deduplicate bygp.getPath(). Test with a hand-builtGradleProjectmarker, because the tooling API can't populate configuration errors (T/DependencyResolutionDiagnosticTest:75-76).
- Where:
E. Relocations: RelocatedDependencyCheck and migrations.csv
-
E1
RelocatedDependencyCheckmisses Kotlin DSL, platforms, catalogs and parents (#219)Details
- Where:
M/RelocatedDependencyCheck:126-150(aGroovyIsoVisitorwithDependencyHandlerSpec *(..)) and:229-252. - Problem:
- PROBED:
buildGradleKtswithimplementation("commons-lang:commons-lang:2.6")gets no marker and no row. Fixed in #219. - CONFIRMED: also missed are:
platform(..)andenforcedPlatform(..). Fixed in #219.libs.versions.toml. Fixed in #219.plugins { id .. }- Maven
<parent>and<extensions>. Fixed in #219 (marked, not changed). ${property}coordinates, whose raw text is looked up. Fixed in #219.
- CONFIRMED:
group: someVarand"${someVar}"look up the variable name (:181-192), which can never match.
- PROBED:
- Fix: use the
GradleDependencytrait, which covers Groovy and Kotlin, string and map notation, and platforms. Read resolved Maven values viagetResolutionResult().getPom().getValue(..). Add<parent>.
- Where:
-
E2
RelocatedDependencyCheck(changeDependencies=true)neither changes nor marks Maven plugins (#219)Details
- Where:
M/RelocatedDependencyCheck:244-249→:254-268. - Problem (PROBED): for a relocated
<plugin>,maybeUpdateschedulesChangeDependency, which never touches<plugin>coordinates, and it also skips theSearchResult. The result is no change and no marker, only a data table row. - Fix: use
ChangePluginGroupIdAndArtifactId, or keep the marker. Decide this together with E3, since the probed plugin relocation is itself wrong.
- Where:
-
E3
changeDependencies=true:latest.release, one hop, and invented coordinates (#219)Details
- Where:
M/RelocatedDependencyCheck:217-219,261-263("latest.release") and:273-280(the group-only fallback). - Problem (CONFIRMED):
- Version: the change always moves to
latest.release, across majors and namespaces. Examples arejavax.servlet-api→jakarta.servlet-api6.x, Jackson 2 →tools.jackson3.x andhttpclient→httpclient5. A probe of the existing Gradle test movedmysql-connector-java:8.0.31tocom.mysql:mysql-connector-j:26.10.0. - Chains: only one hop is followed. 55 rows point at a coordinate that is itself relocated, e.g.
javax.servlet:servlet-api→javax.servlet:javax.servlet-api→jakarta.servlet:jakarta.servlet-api, so reaching the end takes N runs. - Invented coordinates: the group-only fallback produces artifacts that don't exist, and every one of these returns 404 on Central:
org.apache.groovy:groovy-eclipse-compiler, whichT/RelocatedDependencyCheckTest:196-237expectscom.github.spotbugs:jsr305tools.jackson.datatype:jackson-datatype-jdk8, merged into databind in Jackson 3
- SUSPECTED:
ChangeDependencyis aScanningReciperun viadoAfterVisit(..getVisitor()), so its scanner never runs.
- Version: the change always moves to
- Fix: see A4.
- Follow chains to the end, with cycle protection.
- Verify group-only targets against metadata, or drop the fallback.
- Pick a version policy.
- Run
ChangeDependencyas a proper sub-recipe.
- Where:
-
E4
migrations.csvis stale and contains successors that aren't relocations (#219)Details
- No longer refreshed (CONFIRMED):
0da925fdeleted the weeklymigrations.ymlworkflow, because it pushed straight tomain. The CSV has been frozen sinceb74cf0c(2026-10-12). It is regenerated wholesale, so data fixes must go upstream to jonathanlermitage/oga-maven-plugin, or into a local override layer. - Successors flagged as relocations (PROBED): every Jackson 2 user gets a marker saying "Relocated to tools.jackson.core:jackson-databind" (CSV
:715-723). Jackson 2 is maintained. Similar rows arerxjava2(:708),commons-httpclient(:131) andlog4j:log4j(:711). - Prose targets: 32 rows, CSV
:679-705,710-711.- They come from
og-unofficial-definitions.json, whereParseDefinitionMigrations:71keeps only the first proposal. - Unofficial and official rows aren't distinguished. M2 in #210 stops the crash.
- They come from
- Targets that return 404 on Central: 24 artifact rows, e.g.:
:13cactus:cactus-ant-13:107,110,121com.azure:azure-keyvault*:283jakarta.websocket-api:jakarta.websocket-client-api(wrong group):352-355org.opensymphony.quartz:*:659-660org.eclipse.jetty.http2:jetty-fcgi-*
- Conflicting duplicates, where the last row wins:
jca:jca(:301-302)org.hibernate:hibernate-infinispan(:466-467)io.quee.ktx.framework:ktx-business-framework(:227-228)net.ju-n:net-ju-n-parent(:335-336)
- Fix:
- Restore the refresh as a job that opens a PR. Out of scope for #219.
- Add a
sourcecolumn (official or unofficial), and skip unofficial rows in change mode. Fixed in #219. - Filter out non-coordinate targets when parsing. Fixed in #219.
- Report the 404, duplicate and successor rows upstream, or keep a local deny-list. Local deny-list in #219; not yet reported upstream.
- No longer refreshed (CONFIRMED):
- 主要语言
- Java
- 星标
- 18
- 派生
- 12
- 平均合并
- 55 分钟
- 30 天内合并 PR
- 28
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
openrewrite/rewrite-java-dependencies 的其他 Issue
-
enhancement
难度 4/5 3-5 天 新手友好度 48/100
openrewrite/rewrite-java-dependencies#182 · 2 条评论 ·
维护者通常 1 天内回复
查看 openrewrite/rewrite-java-dependencies 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 72/100
aws/aws-emulator#30 · 1 条评论 ·
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 4 天内回复
-
Bug: Minor Status: Triage
难度 2/5 1-3 小时 新手友好度 63/100
GTNewHorizons/GT-New-Horizons-Modpack#27664 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 79/100
openrewrite/rewrite#9835 ·
维护者通常 1 天内回复
-
serviceability
难度 1/5 1 小时以内 新手友好度 65/100
OpenLiberty/open-liberty#36348 ·
维护者通常 1 天内回复