spring-gradle-plugins / dependency-management-plugin

A Gradle plugin that provides Maven-like dependency management functionality
684 stars 85 forks source link

Support for Isolated Projects #380

Open michaelbull opened 3 months ago

michaelbull commented 3 months ago

Gradle has introduced the isolated projects feature that is currently in pre-alpha.

Enabling this pre-alpha feature with the io.spring.dependency-management plugin applied reports the following problems:

image

org.gradle.api.InvalidUserCodeException: Cannot access project ':file' from project ':www'
    at org.gradle.configurationcache.ProblemReportingCrossProjectModelAccess$ProblemReportingProject.getGroup(ProblemReportingCrossProjectModelAccess.kt:272)
    at io.spring.gradle.dependencymanagement.internal.VersionConfiguringAction$StandardLocalProjects.getNames(VersionConfiguringAction.java:124)
    at io.spring.gradle.dependencymanagement.internal.VersionConfiguringAction$CachingLocalProjects.getNames(VersionConfiguringAction.java:145)
    at io.spring.gradle.dependencymanagement.internal.VersionConfiguringAction.isDependencyOnLocalProject(VersionConfiguringAction.java:95)
    at io.spring.gradle.dependencymanagement.internal.VersionConfiguringAction.execute(VersionConfiguringAction.java:63)
    at io.spring.gradle.dependencymanagement.internal.VersionConfiguringAction.execute(VersionConfiguringAction.java:37)
    at java.base/java.lang.Thread.run(Thread.java:829)

The stacktrace points towards the VersionConfiguringAction.

        @Override
        public Set<String> getNames() {
            Set<String> names = new HashSet<>();
            for (Project localProject : this.project.getRootProject().getAllprojects()) {
                names.add(localProject.getGroup() + ":" + localProject.getName());
            }
            return names;
        }

This code ends up only being used by this method:


    private boolean isDependencyOnLocalProject(Project project, DependencyResolveDetails details) {
        return this.localProjects.getNames().contains(getId(details));
    }

    @Override
    public void execute(DependencyResolveDetails details) {
        logger.debug("Processing dependency '{}'", details.getRequested());
        if (isDependencyOnLocalProject(this.project, details)) {
            logger.debug("'{}' is a local project dependency. Dependency management has not been applied",
                    details.getRequested());
            return;
        }

                ...

It seems like it is collecting all dependency names by asking the root project for all subproject names and then comparing their names to ensure that the plugin does not apply to local subproject dependency resolution. Collecting all the names via the root project is breaking the principal of project isolation.

I wonder if there is a simpler way to determine whether the plugin is a local project dependency, to accordingly ignore it when applying a controlled version? To comply with the project isolation feature, the plugin fundamentally cannot break out of the subproject it's applied to and query the root project for its subprojects, however this may not be feasible with the design of the plugin.

Let me know if you have any ideas and I'd be happy to help make the changes necessary to support the feature.

wilkinsona commented 3 months ago

A couple of options come to mind:

  1. Try using Settings#getRootProject and ProjectDescriptor#getChildren to figure out the names of all of the projects.
  2. Disable the skipping of "local" projects when isolated projects are enabled

Assuming that it works, one is probably preferable.

michaelbull commented 3 months ago

With regards to option 2, I think we can still have it analysing local projects, but only those ones that are subprojects of the project the plugin is applied to. According to the build logic constraints, we can still safely call Project.getAllprojects, which returns "the set containing this project and its subprojects". This does however result in different behaviour for projects that are siblings of the one you've applied the plugin to, vs ones that are children (the siblings aren't checked, the children are).

I'll test a local project with a call to getRootProject and see if it complains.