Mark build as contributing to buildscript classpath by 6hundreds · Pull Request #36872 · gradle/gradle
Fixes #36177
Current design overview
In case of included builds, we decide how to store it in CC by checking does it have a work , what is checking the contents of the build's execution plan.
When there is a work:
- we store the build as
IncludedBuildmeaning storing its projects asProjectWithWork:
val projects = collectProjects(buildState.projects, scheduledWork.scheduledNodes, gradle.serviceOf()) writeProjects(gradle, projects) - when we load, we register and create
projects with workof the build:
val projects = readProjects(gradle, build) build.createProjects()
When there is no work:
- we store the build as
BuildWithNoWorkmeaning storing its projects asProjectWithNoWork:
write(ProjectWithNoWork(project.projectPath, project.projectDir, project.mutableModel.buildFile)) - when we load, we just load
BuildWithNoWorkwithout actual project registration in ProjectRegistry:
withGradleIsolate(rootBuild.gradle, userTypesCodec) { val identityPath = Path.path(readString()) val hasProjects = readBoolean() if (hasProjects) { val rootProjectName = readString() val projects: List<ProjectWithNoWork> = readList().uncheckedCast() BuildWithNoWork(identityPath, rootProjectName, projects) } else { BuildWithNoProjects(identityPath) }
Absence of restored project registration in ProjectRegistry is an important aspect, since if we want to have a Project as an input for the work, we have to have it restored properly after CC.
Included plugin builds
In order to provide precompiled plugins to the root build, the task graph of these builds executed early as a part of build logic building process, triggered here:
| @Override | |
| public ClassPath resolveClassPath(Configuration classpathConfiguration, ScriptClassPathResolutionContext resolutionContext) { | |
| return buildOperationRunner.call(new CallableBuildOperation<ClassPath>() { | |
| @Override | |
| public ClassPath call(BuildOperationContext context) { | |
| return buildQueue.build( | |
| currentBuild, | |
| taskIdentifiersForBuildDependenciesOf(classpathConfiguration), | |
| () -> scriptClassPathResolver.resolveClassPath(classpathConfiguration, resolutionContext) | |
| ); | |
| } |
resulting setting EMPTY execution plan for the included build BEFORE CC checks the work presence:
| try (ProjectExecutionServiceRegistry projectExecutionServices = new ProjectExecutionServiceRegistry(globalServices)) { | |
| return executeWithServices(projectExecutionServices); | |
| } finally { | |
| executionPlan.close(); | |
| executionPlan = FinalizedExecutionPlan.EMPTY; | |
| } |
Having said that, included plugin builds always have no work at the CC store moment and being stored as BuildWithNoWork
Included library(non-plugin) builds
The goal of these type of builds is to provide dependency substitutions for the root builds, so the execution of the task graph is postponed(since it doesn't go through build logic building process). In other words, these builds always have some work at the CC store moment and being stored as IncludedBuild, meaning store/reload all its projects.
However, when a project of such a build is being used as a part of buildscript classpath(apply plugins is somewhat similar to this, as it also alters buildscript classpath), we have to go through build logic building process, where we execute task graph early, forcing build to be stored as BuildWithNoWork.
This PR
Tries to mark an included build if it contributes to buildscript classpath(either directly via buildscript{} block or providing a plugin) , to treat it similarly as build having a work.
As we now treat Included build logic build as "having a work", we emit additional Calculate work graph operation(which effectively no op as there are no any nodes for schedule) for included build also, what is making the test failing.
Reviewing cheatsheet
Before merging the PR, comments starting with
- ❌ ❓must be fixed
- 🤔 💅 should be fixed
- 💭 may be fixed
- 🎉 celebrate happy things