Repository navigation
Conversation
Signed-off-by: GT <gregjotau@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
BootJarandBootWarcurrently construct a map of every local project's coordinates by reading other projects' mutablegroupandversion. This fails while the tasks are being created under strict Isolated Projects, before any packaging occurs. The path-only map also assigns the wrong coordinates when a main-build project and an included-build project share a path, affecting custom layers and reachability metadata even without isolation.This PR resolves project coordinates lazily from the dependency graph that produced the archive's artifacts. It also proposes an explicit compatibility boundary for the public artifact-only registration API. Addresses gh-43755.
Why the Gradle prerequisite is now actionable
Gradle's maintainer confirmation establishes that, for a
ProjectComponentIdentifier,ResolvedComponentResult.getModuleVersion()reliably supplies the producer project's group/name/version under isolation. These are project coordinates, not Maven publication coordinates. Synthetic graph roots are different and must not be used as project-coordinate substitutes; Gradle 10 will also use anonymous roots for ordinary configurations.The implementation uses that contract. It does not infer coordinates from capabilities or request a new Gradle API. This is a different approach from the earlier capability-based #51311.
Proposed API and compatibility decision
Add this overload to
BootArchive:The artifacts and root must come from the same configuration. An artifact view can supply the artifacts while its owning configuration supplies the root.
The interface method has a default implementation that calls the existing artifact-only overload, preserving compatibility with independent implementations of
BootArchive.BootJarandBootWaroverride the new method to consume the graph. Their built-in runtime-classpath wiring uses it automatically.The existing single-provider method retains local-project coordinate lookup for ordinary builds, but the lookup runs only if that method is called, rather than during every archive task's construction. Existing custom archive callers keep their method signature and local-project lookup. The legacy snapshot is taken at explicit registration rather than construction; it is no longer collected for tasks that never use that overload. They must move to the graph overload to use Isolated Projects. The legacy overload is not silently redirected to the runtime classpath: its artifacts may originate from an entirely different configuration.
This is the central policy choice for review: preserve the legacy API's ordinary-build behavior and give callers an explicit migration path, rather than guess project coordinates, silently stop matching custom layers, or break existing implementations by adding an abstract interface method. The new default preserves independent implementations; it does not imply that an arbitrary third-party implementation itself becomes isolation-compatible.
Why each implementation mechanism is present
ComponentIdentifiermoduleVersiononly for project identifiersModuleComponentIdentifier.Projector dependency graph is retained in the snapshot used for packaging and configuration-cache restoration.All new production logic is confined to archive metadata resolution, the two archive implementations, their Java/WAR wiring, and the additive interface method. The documentation explains the custom-archive migration rather than enabling isolation globally.
Alternatives considered
allprojectsinto a provider: delaying cross-project model access does not make it isolated and risks retaining aProjectin task state.runtimeClasspath's graph behind the old API: this changes semantics for custom configurations and artifact views.Configurationin the new API: convenient for the built-in case, but prevents callers from registering a filtered or transformed artifact view alongside the correct graph. A provider pair preserves that flexibility without retaining the mutable configuration.Validation
Executed against upstream main
11778bdc24f:bootJartest fails atProject.groupduring task construction; the normal composite test assignsincluded-lib.jarto the main project's custom layer instead of the included project's layer.BootJarIntegrationTestsandBootWarIntegrationTests: 106 cases, zero failures, six existing version-specific skips (100 executed).bootJar,bootWar, andbootBuildImagepassed under strict isolation on all three Gradle versions (three additional cases).Commands:
The Tooling API and Kotlin DSL cases were added after the 122-case matrix and run separately with
-PtoolchainVersion=17and the matching test filters (six additional cases; 128 targeted executions in total, no failures/skips).A packaged patch was also tested against a real multi-project Kotlin application on Gradle 9.8.2. An external init script substituted only the locally built plugin artifact; the application source/configuration was not changed, and a reflection assertion verified the new overload was actually loaded.
:web-app:build -x test --isolated-projectspassed (448 tasks), then the identical command reused the configuration cache. All 3,474 entry names and uncompressed file contents in its executable archive matched the normal-build baseline exactly; ZIP metadata was not compared. This consumer uses native BOM platforms. No production deployment was performed.The committed integration fixture deliberately combines two
:libraryprojects in different builds, a transitive included-build dependency, a late producer version, a renamed archive, an unrelated selected capability, and publication coordinates different from project coordinates. These are independent ways a shortcut can appear to work while selecting the wrong metadata.Separate tests cover normal/isolated JAR and WAR packaging, forced archive execution after configuration-cache reuse, coordinate-only input invalidation with byte-identical library JARs, the legacy custom-archive overload, the graph overload with a filtered artifact view, image-task realization without Docker execution, project reachability-metadata overrides with layers disabled, Tooling API task-model construction, and direct Kotlin DSL use of the new overload. The Tooling API test supplies the same unpublished plugin classpath explicitly because model requests do not use TestKit’s classpath injection. Focused tests cover lazy snapshotting, synthetic roots, cyclic/transitive graphs, mismatched providers, missing coordinates, external/opaque components, and compatibility of the interface default.
Scope and limitations
This changes Boot's post-resolution archive metadata path. It does not fix
io.spring.dependency-management's separate pre-resolution local-GA exclusion rule (#380). Resolving that rule cannot consume the completed graph of the resolution it is currently constructing. Tests here use native Gradle dependency handling and do not suppress violations.The legacy artifact-only path remains incompatible with strict isolation for multi-project builds, and retains its historical path-based lookup. Custom callers opt into the graph overload for composite correctness and isolation. This is intentional compatibility behavior, not a claim of complete support for every build plugin or custom archive implementation.
AI assistance: this implementation, its tests, and the analysis were prepared with Codex. Validation results describe commands actually run locally.