Repository navigation
Find tasks lazily in plugin-base and protobuf-setup-plugins - #199
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stop creating tasks which a build may never run (#198): - Add `Project.javaCompileTasksFor()` and `kotlinCompileTasksFor()`, returning live `TaskCollection`s, and deprecate `findJavaCompileFor()` and `findKotlinCompileFor()`. The Kotlin variant matches by name, so it works without the Kotlin Gradle plugin on the classpath. - Make `GradleTask.Builder.applyNowTo()` register the task and wire its dependencies via providers. `GradleTask` now holds a `TaskProvider`, exposed via `getTaskProvider()`. The builder state is copied, and the following task is checked before the new task is registered. - `DescriptorSetFilePlugin` adds the descriptors directory to the resources as built by `GenerateProtoTask` instead of iterating over all `ProcessResources` tasks. `setup()` runs inside the configuration action of `GenerateProtoTask`, where Gradle forbids `configureEach()` on other tasks. - `GeneratedSourcePlugin` no longer calls `setupKotlinCompile()`, which created the Kotlin compilation tasks. The generated source directories already make compilation depend on `GenerateProtoTask`. - `TaskDependencies.dependsOn()` recognizes task providers and task collections. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the `idea` plugin applied, the Protobuf plugin reads the source
directories of the source sets once the project is evaluated, to add
them to the IDE sources. Doing so created `GenerateProtoTask` for the
first time, and `GeneratedSourcePlugin.setup()` modified the directories
being iterated, failing the build with `ConcurrentModificationException`.
`ProtobufSetupPlugin` now creates the tasks in a `generateProtoTasks {}`
action, which the Protobuf plugin runs first, like the Spine Compiler
does. The `afterEvaluate` block creating the tasks is kept for the tasks
registered later.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Avoid `!!` in `GradleTaskBuilderSpec`. - Name the forced creation of `GenerateProtoTask`s in `ProtobufSetupPlugin` and explain why both creation points exist. - Say that `setupKotlinCompile()` is no longer needed. - Make the `GradleTask` Javadoc precise about when the task is created and which projects `insertAfterAllTasks()` covers. - Share `writeSampleProto()` via `ProtobufPluginTest`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
🟢 Approved
The review reports no active issues requiring resolution before approval.
No open issues 🎉
What changed in this PR
This PR reduces unnecessary task creation in ToolBase’s Gradle plugins, addressing #198, and fixes the configuration failure when generated-source setup runs alongside the idea plugin.
Changes:
- Adds lazy compile-task lookup APIs and provider-based task registration and dependency checks.
- Preserves compilation and resource dependencies through generated directories, and adjusts Protobuf setup timing for IDE compatibility.
- Adds regression coverage and updates the publication version and dependency reports to
2.0.0-SNAPSHOT.429.
| File | Description |
|---|---|
version.gradle.kts |
Bumps the publication version to .429. |
protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/ProtobufPluginTest.kt |
Adds a shared sample-proto helper. |
protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/LazyTaskWiringSpec.kt |
Tests lazy task wiring and Kotlin compilation dependencies. |
protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePluginSpec.kt |
Adds generated-source coverage with idea applied. |
protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/DescriptorSetFilePluginSpec.kt |
Adds descriptor-generation coverage with idea applied. |
protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/BuildCacheSpec.kt |
Reuses the shared sample-proto helper. |
protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/ProtobufSetupPlugin.kt |
Initializes generation tasks before IDE source-directory inspection. |
protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt |
Removes eager Kotlin task setup and deprecates its helper. |
protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/DescriptorSetFilePlugin.kt |
Wires resource dependencies through a directory marked builtBy. |
plugin-base/src/test/kotlin/io/spine/tools/gradle/task/TaskDependenciesSpec.kt |
Tests dependency detection through providers and collections. |
plugin-base/src/test/kotlin/io/spine/tools/gradle/task/GradleTaskTest.kt |
Checks provider access for an existing task. |
plugin-base/src/test/kotlin/io/spine/tools/gradle/task/GradleTaskBuilderSpec.kt |
Tests lazy registration, builder snapshots, and dependency wiring. |
plugin-base/src/test/kotlin/io/spine/tools/gradle/project/ProjectExtsSpec.kt |
Tests lazy compile-task lookup and configuration. |
plugin-base/src/main/kotlin/io/spine/tools/gradle/project/ProjectExts.kt |
Adds lazy compile-task collections and deprecates eager lookups. |
plugin-base/src/main/java/io/spine/tools/gradle/task/TaskDependencies.java |
Recognizes provider and collection dependencies without creating tasks. |
plugin-base/src/main/java/io/spine/tools/gradle/task/GradleTask.java |
Uses task providers and snapshots builder configuration. |
docs/dependencies/pom.xml |
Updates the documented project version. |
docs/dependencies/dependencies.md |
Refreshes report versions and generation timestamps. |
Review effort: Balanced
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #199 +/- ##
============================================
- Coverage 92.18% 92.08% -0.11%
- Complexity 841 846 +5
============================================
Files 163 162 -1
Lines 3172 3182 +10
Branches 373 381 +8
============================================
+ Hits 2924 2930 +6
- Misses 116 122 +6
+ Partials 132 130 -2 🚀 New features to boost your workflow:
|
Covers the branches where a task provider or a task collection is checked after the dependency is already found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The last known use of `GradleTask.Builder`, `CleaningPlugin` of core-jvm-compiler, now registers its task via the Gradle API directly (SpineEventEngine/core-jvm-compiler#123). `TaskContainer.register()` and `TaskProvider.configure()` wire a task into the build lifecycle lazily without the wrapper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The class has no users in the SpineEventEngine organization, only its own test. Its `addArgs()` also created every `JavaCompile` task of the project. The test helpers `ProjectTasks` and `ProjectConfigurations` served only that test, so they are removed too. This removes public API of `plugin-base`, so the version is rounded up as a breaking change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`afterEvaluate { tasks.findByName(sourcesJar) }` created the task in
every build. A `named(Spec)` collection sets the dependency without
creating the task, and includes a `sourcesJar` registered after the
plugin is applied.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #198.
plugin-baseandprotobuf-setup-pluginsno longer create tasks that a build may never run. Each call site listed in the issue is now lazy. So is one more that the issue's measurement hid. The PR also fixes aConcurrentModificationExceptionthat broke builds applyingideatogether with these plugins.This is a breaking change for
plugin-base, because it removes the unusedJavaCompileTasks. So the version is2.0.0-SNAPSHOT.430.New API
In
plugin-base,io.spine.tools.gradle.project(ProjectExts.kt):Project.javaCompileTasksFor(sourceSet): TaskCollection<JavaCompile>Project.kotlinCompileTasksFor(sourceSet): TaskCollection<Task>. It matches by name only, so it works when the Kotlin Gradle plugin is not on the classpath (the Compiler has it ascompileOnly). Narrow it withwithType(KotlinCompilationTask::class.java)where needed.findJavaCompileFor()andfindKotlinCompileFor()are deprecated but keep working.GradleTask.getTaskProvider()returns the provider of the task without creating it.SpineEventEngine/compiler#99 and SpineEventEngine/core-jvm-compiler#123 fix their own call sites against ToolBase
.428, so they don't depend on this PR. To remove the duplicated logic, these repos should adopt the API when they bump ToolBase to.430:createTasks()derivescompileJavaTaskNameandgetCompileTaskName("Kotlin")itself. UsejavaCompileTasksFor()andkotlinCompileTasksFor()instead, and keep the KSP task lookup.CommonKspSettingsPluginstill calls the deprecatedfindKotlinCompileFor()inafterEvaluate, which createscompile*Kotlin. UsekotlinCompileTasksFor().Important
Gradle throws
DefaultTaskCollection#configureEach(Action) on task set cannot be executed in the current contextwhenconfigureEach {}orTaskProvider.configure {}is called from inside the configuration action of another task. Call the new functions where the task is registered, not inside itsregister {}block. The Compiler'sLaunchSpineCompiler.setDependencies()runs inside such a block today.Changes
findJavaCompileFor()/findKotlinCompileFor(): deprecated in favour of the lazy functions above.DescriptorSetFilePlugin.dependOnProcessResourcesTask(): removed. The issue suggestedwithType<ProcessResources>().named { … }.configureEach {}, but that cannot work here.setup()runs inside the configuration action ofGenerateProtoTask, where Gradle forbids configuring other tasks (see the note above). Instead, the descriptors directory is added tosourceSet.resourcesasfiles(dir).builtBy(generateProto).processResources, and any other consumer of the resources, depends ongenerateProtothrough its inputs.GradleTask.Builder.applyNowTo(): registers the task and wires the dependencies through providers. The following task getsnamed(…).configure { dependsOn(newTask) }.insertAfterAllTasks()still covers only the tasks registered whenapplyNowTo()runs. It checks their names, which does not create them, and depends on their providers.GradleTaskand its builder are now deprecated. ConfigurepreCleanand the gRPCgeneratePrototasks lazily core-jvm-compiler#123 replaces the last known use (CleaningPlugin) withtasks.registerandnamed("clean").configure { dependsOn(…) }, which does the same without the wrapper. The lazy implementation stays for any remaining callers.GeneratedSourcePlugin:setup()no longer callssetupKotlinCompile(), which createdcompile*Kotlin. This call site is not in the issue. It sat behind the Compiler'sfindKotlinCompileFor(), so the Compiler's call was recorded as the first one to create the task. Sincecdeae452, the generated source directories already make compilation depend ongenerateProto.setupKotlinCompile()is deprecated, and its body is unchanged.ArtifactMetaPlugin(jvm-tool-plugins): it no longer createssourcesJarviafindByName()inafterEvaluate. It makes the task depend onwriteArtifactMetaviatasks.named { … }.configureEach {}, which also includes asourcesJarregistered after the plugin is applied. The plugin is applied by the Spine tool repos' own builds, not by consumers likecore-jvm.JavaCompileTasks: removed, along with its test and the test helpers that served only it. Nothing in the SpineEventEngine organization used it, and itsaddArgs()created everyJavaCompiletask of the project.TaskDependencies.dependsOn()(and soGradleTruth'sdependsOn) now recognizesTaskProviderandTaskCollectionentries ofgetDependsOn()without creating tasks. Before, dependencies declared through providers were reported as missing.idea+io.spine.generated-sources: the build failed at configuration withConcurrentModificationException. This also happened onmaster. The Protobuf plugin's ownafterEvaluatereads the source directories for the IDE, and doing so first createdgenerateProto.setup()then modified the directories being iterated.ProtobufSetupPluginnow creates the tasks in aprotobuf.generateProtoTasks {}action, which the Protobuf plugin runs first, as the Compiler already does. TheafterEvaluateblock stays for tasks registered later. As before this PR, thegenerate*Prototasks are created in every build:setup()must change the source sets before anything reads them.Verification
ProjectBuilderspecs record created tasks viatasks.configureEach {}. They check that the wiring creates no tasks and that the dependencies still resolve:ProjectExtsSpec,GradleTaskBuilderSpec,GradleTaskTest,TaskDependenciesSpecandLazyTaskWiringSpec.LazyTaskWiringSpecappliesidea, KGP and both plugins../gradlew helpcreates onlygenerateProto,generateTestProto,helpandclean.compileKotlin --dry-runstill schedulesgenerateProto.setupKotlinCompile()call makes thehelpcheck fail withcompile*Kotlincreated.processResourcesspec fails against the oldDescriptorSetFilePlugin.GeneratedSourcePluginSpecandDescriptorSetFilePluginSpecapplyidea. TheGeneratedSourcePlugincase failed with the CME before the fix../gradlew build dokkaGeneratepasses.Rollout
Consumers load
tool-baseclasses from thecore-jvm-pluginsfat JAR of core-jvm-compiler. The fixes intool-base's own plugins (process*Resourcesandcompile*Kotlinno longer created, theideacrash) reach them in this order:2.0.0-SNAPSHOT.430..430, adopts the API above, and publishes. This PR changes whenProtobufSetupPlugincreates theGenerateProtoTasks, and the Compiler relies on that timing, so its integration tests check this change first.core-jvm-plugins.🤖 Generated with Claude Code