Open lacasseio opened 3 years ago
Starting with Gradle 7.0, a new service was introduced DependenciesAccessors
. This service is queried (created) in the beforeEvaluated
project hook. Gradle seems to be dynamically loading APIs (such as JARs) outside of the “API”. The service coincidentally loads DEPENDENCIES-EXTENSION-COMPILER
class path. A normal initialization seems to look like this:
private final ModuleRegistry moduleRegistry = new DefaultModuleRegistry(CurrentGradleInstallation.get())
private final ClassPathRegistry classPathRegistry = new DefaultClassPathRegistry(new DefaultClassPathProvider(moduleRegistry))
private final ClassPath classPath = classPathRegistry.getClassPath("DEPENDENCIES-EXTENSION-COMPILER")
The CurrentGradleInstallation
fails with the redistribute Gradle API as the JAR path is unexpectedly under caches/modules-2/files-2.1/…
instead of being under the caches/<version>/generated-gradle-jars/…
. We would need to rewrite the logic under CurrentGradleInstallation
or trick in some way the “loading” of additional JARs. The classes are already in the generated Gradle JAR but Gradle is opinionated in loading extra JARs.
This issue is somewhat related to a problem with the TestKit API JAR when it tries to detect the current Gradle version. However, it is outside the scope of this issue.
We may be forced to rerelease the Gradle APIs for version 7.+ with a patch to the API. I don't want to start patching the API, but if it's the only way, we may have to do this. A disclosure will have to be bundled with the Gradle API if we do apply a patch.
Instead of fixing internal APIs, we could allow some way to mock Project
, Settings
and Gradle
. Assuming we split unit, integration and functional testing across the following boundaries:
Project
, Settings
and Gradle
boundary, i.e.new SomePlugin(/*injection*/).apply(mockProject())
.ProjectBuilder
to create functional Project
instance. Unfortunately, there is no equivalent for Settings
and Gradle
.We would benefit from having a mock-ish API for Project
, Settings
, and Gradle
. I would assume the mock-ish API would not truly apply plugin, i.e. project.getPluginManager().apply('...')
, but instead simply record the plugin request. For cases where the plugin under test would then request an extension from a nested plugin, users would have to provide a mock. The same would be for containers that would give some access to some APIs and track some calls but not all of them. I would assume we would disallow eager APIs so Provider
can be used as a clear boundary. As for the afterEvaluate
issue expressed here, we would assert afterEvaluate
action being registered which we can then test individually. There is a fine line between unit and integration testing as ProjectBuilder
can be expensive in the longer run. It also doesn't provide a good symmetry for the other important Gradle APIs (Settings
and Gradle
).
We should investigate if we can position the generated JARs (copy) to the correct place (without colliding with actual Gradle JARs) so the assumption baked into Gradle can still work.
ProjectInternal#evaluate()
fails with: