From 96367449e1b90ac313a77d4c667d4942c6ab9e8f Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 18:18:26 +0000 Subject: [PATCH 01/14] Bump version -> `2.0.0-SNAPSHOT.082` Co-Authored-By: Claude Opus 5.5 --- version.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle.kts b/version.gradle.kts index b1e4fe0632..5a73218bab 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -18,7 +18,7 @@ * This version is also used by integration test projects. * E.g. see `tests/consumer/build.gradle.kts`. */ -private val compilerVersion = "2.0.0-SNAPSHOT.081" +private val compilerVersion = "2.0.0-SNAPSHOT.082" extra.set("compilerVersion", compilerVersion) /** From 6a67977ebd8b67f12f8b81194f970fe168e9cc9d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 18:18:38 +0000 Subject: [PATCH 02/14] Arrange task dependencies without creating tasks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop the Compiler Gradle plugin from creating the `launch*SpineCompiler`, `compile*Java`, `compile*Kotlin`, and `ksp*Kotlin` tasks by name while the projects are configured (#98). - Register the launch and clean tasks via `sourceSets.configureEach`, which also serves source sets added later, instead of an `afterEvaluate` fallback. - Make the Java, Kotlin, and KSP tasks depend on the launch task via `tasks.named { … }.configureEach`, which also covers tasks registered later. - Let the launch task depend on its `generate*Proto` task by provider. Gradle forbids configuring other tasks from a lazy configuration action, so the `GenerateProtoTask` action no longer touches the launch task. - Add `TaskLocator.exists()` and `named()`, which create no tasks. `generate*Proto` tasks are still configured eagerly: configuring them rewrites the source set directories, which must happen before the Protobuf Gradle Plugin passes them to the IDEA plugin. A lazy action fails that with `ConcurrentModificationException`. Co-Authored-By: Claude Opus 5.5 --- .agents/tasks/lazy-task-wiring.md | 58 ++++ .../tools/compiler/gradle/api/TaskLocator.kt | 55 ++-- .../compiler/gradle/api/TaskLocatorSpec.kt | 63 +++-- .../gradle/plugin/LaunchSpineCompiler.kt | 31 +- .../tools/compiler/gradle/plugin/Plugin.kt | 133 ++++----- .../gradle/plugin/ProjectConfigSpec.kt | 28 +- .../compiler/gradle/plugin/TaskWiringSpec.kt | 266 ++++++++++++++++++ 7 files changed, 483 insertions(+), 151 deletions(-) create mode 100644 .agents/tasks/lazy-task-wiring.md create mode 100644 gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/TaskWiringSpec.kt diff --git a/.agents/tasks/lazy-task-wiring.md b/.agents/tasks/lazy-task-wiring.md new file mode 100644 index 0000000000..b309ff075e --- /dev/null +++ b/.agents/tasks/lazy-task-wiring.md @@ -0,0 +1,58 @@ +--- +slug: lazy-task-wiring +branch: claude/lazy-task-wiring-a189e2 +owner: claude +status: in-review +started: 2026-10-29 +--- + +## Goal + +The Compiler Gradle plugin creates no tasks by name while the projects are +configured (SpineEventEngine/compiler#98). The dependencies between the launch, +`generate*Proto`, `compile*Java`, `compile*Kotlin`, and `ksp*Kotlin` tasks stay +as they are. + +## Context + +- Gradle forbids `named(…).configure {}`, `configureEach {}`, and + `afterEvaluate {}` inside a lazy task configuration action (probed on 9.8.2: + "cannot be executed in the current context"). So the `generateProto` + `configureEach` action cannot wire the launch task, as the issue suggests. + The launch task wires itself to its `generateProto` task instead. +- The `afterEvaluate` fallback for late source sets depended on that wiring. + `sourceSets.configureEach` replaces it. +- `configureGenerateProtoTasks()` stays eager. Configuring a `GenerateProtoTask` + rewrites its source set's directories (tool-base `configureSourceSetDirs()`). + That must happen before protobuf-gradle-plugin's `postConfigure` hands the + directories to the IDEA plugin. With `configureEach`, reading them creates + the task mid-iteration and the build fails with `ConcurrentModificationException`. + The Protobuf plugin creates the tasks there anyway when `idea` is applied. + +## Plan + +- [x] `TaskLocator`: add `exists()` and `named()`; keep `find()` / `get()`. +- [x] `createTasks()`: `sourceSets.configureEach`; wire compile and KSP tasks with + `tasks.named { … }.configureEach { dependsOn(launchTask) }`. +- [x] `configureGenerateProtoTasks()`: the action configures only the + `GenerateProtoTask` itself; iteration stays eager (see Context). +- [x] `LaunchSpineCompiler.setDependencies()`: depend on `generate*Proto` by provider; + drop `findJavaCompileFor()` / `findKotlinCompileFor()`. +- [x] Tests: no tasks created at configuration time; dependencies still set; + late source set and late KSP task; `generateProto` gets the Compiler plugin + and the source set gets the generated directories; `idea` applied. +- [x] `./gradlew build`; measure a real consumer with the task stats. + `ksp-test` fixture, `./gradlew help`: `.081` created 14 of 53 tasks, `.082` + created 6 (the `launch*`, `compile*Java`, `compile*Kotlin`, `ksp*Kotlin` tasks + are no longer created). In `tests/`, the same tasks are now created first by + `buildSrc`'s `DokkaExts.disableDocumentationTasks` (SpineEventEngine/config#820). + +## Log + +- 2026-10-29 — drafted and started. +- 2026-10-29 — `configureEach` for `generateProto` broke `integrationTest` (CME with + `idea`); reverted that call site to eager iteration, added a regression test. +- 2026-10-29 — `gradle-review`: no blockers. Added tests for the `clean` wiring, + `protoSourceDirs` contents, and the Kotlin compile task; `createCleanTask()` takes + the launch task provider. Not staged for commit: the version bump and dependency + reports (separate commits per the version policy). diff --git a/gradle-api/src/main/kotlin/io/spine/tools/compiler/gradle/api/TaskLocator.kt b/gradle-api/src/main/kotlin/io/spine/tools/compiler/gradle/api/TaskLocator.kt index 91927ee2c3..b8a5cf5fa8 100644 --- a/gradle-api/src/main/kotlin/io/spine/tools/compiler/gradle/api/TaskLocator.kt +++ b/gradle-api/src/main/kotlin/io/spine/tools/compiler/gradle/api/TaskLocator.kt @@ -1,27 +1,15 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. */ package io.spine.tools.compiler.gradle.api @@ -29,10 +17,14 @@ package io.spine.tools.compiler.gradle.api import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.TaskProvider /** * Abstract base for utilities finding tasks of a certain type by * the [provided name pattern][nameFor]. + * + * The [exists] and [named] functions do not make Gradle create a task registered + * but not yet created. Prefer them to [find] and [get] during the configuration phase. */ public abstract class TaskLocator { @@ -43,6 +35,10 @@ public abstract class TaskLocator { /** * Obtains an instance of the task in the given project for the specified source set. + * + * Creates the task if it is registered but not yet created. + * + * @see named */ public fun get(project: Project, sourceSet: SourceSet): Task { val name = nameFor(sourceSet) @@ -52,10 +48,31 @@ public abstract class TaskLocator { /** * Obtains an instance of the task in the given project for the specified source set. * + * Creates the task if it is registered but not yet created. + * * @return the task or `null` if there is no task created for this source set + * @see exists */ public fun find(project: Project, sourceSet: SourceSet): Task? { val name = nameFor(sourceSet) return project.tasks.findByName(name) } + + /** + * Tells if the given project has the task for the specified source set. + * + * Unlike [find], does not create the task if it is registered but not yet created. + */ + public fun exists(project: Project, sourceSet: SourceSet): Boolean = + nameFor(sourceSet) in project.tasks.names + + /** + * Obtains a provider of the task in the given project for the specified source set. + * + * Unlike [get], does not create the task if it is registered but not yet created. + * + * @throws org.gradle.api.UnknownTaskException if there is no task for this source set + */ + public fun named(project: Project, sourceSet: SourceSet): TaskProvider = + project.tasks.named(nameFor(sourceSet)) } diff --git a/gradle-api/src/test/kotlin/io/spine/tools/compiler/gradle/api/TaskLocatorSpec.kt b/gradle-api/src/test/kotlin/io/spine/tools/compiler/gradle/api/TaskLocatorSpec.kt index 41c95b930b..fa075de145 100644 --- a/gradle-api/src/test/kotlin/io/spine/tools/compiler/gradle/api/TaskLocatorSpec.kt +++ b/gradle-api/src/test/kotlin/io/spine/tools/compiler/gradle/api/TaskLocatorSpec.kt @@ -1,33 +1,23 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. */ package io.spine.tools.compiler.gradle.api import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeSameInstanceAs import io.spine.tools.gradle.project.sourceSets import org.gradle.api.Project @@ -58,6 +48,15 @@ internal class TaskLocatorSpec { private val launchTask = project.tasks.register(CompilerTask.nameFor(main)) private val cleanTask = project.tasks.register(SpineCompilerCleanTask.nameFor(main)) + /** + * The names of the tasks that Gradle created after the [launchTask] and + * the [cleanTask] were registered. + */ + private val created = mutableListOf().also { names -> + project.tasks.named { it == launchTask.name || it == cleanTask.name } + .configureEach { names.add(it.name) } + } + @Test fun `get the launch task via 'CompilerTask'`() { CompilerTask.get(project, main) shouldBeSameInstanceAs launchTask.get() @@ -95,4 +94,30 @@ internal class TaskLocatorSpec { shouldThrow { CompilerTask.get(project, test) } shouldThrow { SpineCompilerCleanTask.get(project, test) } } + + @Test + fun `tell if a task exists without creating it`() { + CompilerTask.exists(project, main) shouldBe true + SpineCompilerCleanTask.exists(project, main) shouldBe true + CompilerTask.exists(project, test) shouldBe false + SpineCompilerCleanTask.exists(project, test) shouldBe false + + created.shouldBeEmpty() + } + + @Test + fun `provide a task without creating it`() { + val launchTaskProvider = CompilerTask.named(project, main) + val cleanTaskProvider = SpineCompilerCleanTask.named(project, main) + + created.shouldBeEmpty() + launchTaskProvider.get() shouldBeSameInstanceAs launchTask.get() + cleanTaskProvider.get() shouldBeSameInstanceAs cleanTask.get() + } + + @Test + fun `fail to provide a task for a source set that does not have one`() { + shouldThrow { CompilerTask.named(project, test) } + shouldThrow { SpineCompilerCleanTask.named(project, test) } + } } diff --git a/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt b/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt index 6724b033a4..ea7c46712f 100644 --- a/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt +++ b/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt @@ -28,8 +28,7 @@ import io.spine.tools.compiler.gradle.api.info import io.spine.tools.compiler.params.ParametersFileParam import io.spine.tools.compiler.params.WorkingDirectory import io.spine.tools.compiler.params.pipelineParameters -import io.spine.tools.gradle.project.findJavaCompileFor -import io.spine.tools.gradle.project.findKotlinCompileFor +import io.spine.tools.protobuf.gradle.ProtobufTaskName import io.spine.tools.protobuf.gradle.containsProtoFiles import java.io.File import java.io.File.pathSeparator @@ -55,6 +54,7 @@ import org.gradle.api.tasks.OutputDirectories import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.TaskProvider import org.gradle.process.CommandLineArgumentProvider /** @@ -306,17 +306,14 @@ internal fun LaunchSpineCompiler.applyDefaults(sourceSet: SourceSet) { } /** - * Arranges the dependencies of this task that can be resolved by the time the - * Compiler plugin is applied. + * Arranges the dependencies of this task. * * Makes this task depend on the build of the configurations used to run the Compiler, - * and makes the Java and Kotlin compilation tasks depend on this task. + * and on the [GenerateProtoTask] of the given [sourceSet], if the project has one. * - * The dependency of the Kotlin Symbol Processing (KSP) task is arranged separately - * after the project is evaluated because the KSP task is not yet registered by the - * time the Compiler plugin is applied. + * The dependencies of other tasks on this task are arranged when this task is registered. * - * @see [Project.arrangeKspTaskDependency][io.spine.tools.compiler.gradle.plugin.arrangeKspTaskDependency] + * @see [Project.makeCodeTasksDependOn][io.spine.tools.compiler.gradle.plugin.makeCodeTasksDependOn] */ private fun LaunchSpineCompiler.setDependencies(sourceSet: SourceSet) { val project = project @@ -324,9 +321,10 @@ private fun LaunchSpineCompiler.setDependencies(sourceSet: SourceSet) { project.compilerRawArtifact.buildDependencies, project.userClasspath.buildDependencies, ) - val launchTask = this - project.findJavaCompileFor(sourceSet)?.dependsOn(launchTask) - project.findKotlinCompileFor(sourceSet)?.dependsOn(launchTask) + val generateProtoName = ProtobufTaskName.generateProto(SourceSetName(sourceSet.name)).value() + if (generateProtoName in project.tasks.names) { + consumeProtoFrom(project.tasks.named(generateProtoName, GenerateProtoTask::class.java)) + } } /** @@ -338,10 +336,12 @@ private fun LaunchSpineCompiler.setDependencies(sourceSet: SourceSet) { * at configuration time, so that the parameters file can be written without * querying `Task.dependsOn` at execution time. Such a query is deprecated, * fails in Gradle 10, and is incompatible with the configuration cache. + * + * The call does not make Gradle create the [generateProto] task. */ -internal fun LaunchSpineCompiler.consumeProtoFrom(generateProto: GenerateProtoTask) { +internal fun LaunchSpineCompiler.consumeProtoFrom(generateProto: TaskProvider) { dependsOn(generateProto) - protoSourceDirs.from(generateProto.sourceDirs) + protoSourceDirs.from(generateProto.map { it.sourceDirs }) } /** @@ -350,8 +350,7 @@ internal fun LaunchSpineCompiler.consumeProtoFrom(generateProto: GenerateProtoTa * The function obtains the list of compiled proto files from * [protoSourceDirs][LaunchSpineCompiler.protoSourceDirs] populated from the * [GenerateProtoTask] on which the receiver task depends (as arranged by - * [consumeProtoFrom] called from the `handleLaunchTaskDependency` - * extension in `Plugin.kt`). + * [consumeProtoFrom]). */ private fun LaunchSpineCompiler.createParametersFile() { val params = pipelineParameters { diff --git a/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/Plugin.kt b/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/Plugin.kt index b53ec6ea72..95c480d96c 100644 --- a/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/Plugin.kt +++ b/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/Plugin.kt @@ -18,13 +18,13 @@ package io.spine.tools.compiler.gradle.plugin import com.google.common.collect.ImmutableList -import com.google.errorprone.annotations.CanIgnoreReturnValue import com.google.protobuf.gradle.GenerateProtoTask import com.google.protobuf.gradle.ProtobufExtension import io.spine.annotation.VisibleForTesting import io.spine.format.Format import io.spine.io.replaceExtension import io.spine.string.toBase64Encoded +import io.spine.tools.code.Kotlin import io.spine.tools.code.SourceSetName import io.spine.tools.compiler.gradle.api.Artifacts import io.spine.tools.compiler.gradle.api.Artifacts.compilerBackend @@ -225,56 +225,51 @@ private fun Project.requireProtobufRuntimeOf(source: Configuration, target: Conf } /** - * Creates the [SpineCompilerCleanTask] and [LaunchSpineCompiler] tasks for all source sets - * in this project available by the time of the call. + * Creates the [SpineCompilerCleanTask] and [LaunchSpineCompiler] tasks for each source set + * of this project, including the source sets added by other plugins after this call. * - * There may be cases of source sets added by other plugins after this function is invoked. - * Such cases are handled by the [handleLaunchTaskDependency] function. + * The tasks are registered, not created. Arranging the dependencies on + * the [LaunchSpineCompiler] tasks creates no tasks either. * - * The dependency of the Kotlin Symbol Processing (KSP) task on the [LaunchSpineCompiler] - * task is arranged on [Project.afterEvaluate] because the KSP task is not yet registered - * by the time this plugin is applied. - * - * @see [Project.handleLaunchTaskDependency] - * @see [Project.arrangeKspTaskDependency] + * @see [Project.makeCodeTasksDependOn] */ private fun Project.createTasks() { - sourceSets.forEach { sourceSet -> - createLaunchTask(sourceSet) - createCleanTask(sourceSet) - } - afterEvaluate { - sourceSets.forEach { sourceSet -> - arrangeKspTaskDependency(sourceSet) - } + sourceSets.configureEach { sourceSet -> + val launchTask = createLaunchTask(sourceSet) + makeCodeTasksDependOn(launchTask, sourceSet) + createCleanTask(sourceSet, launchTask) } } /** - * Makes the Kotlin Symbol Processing (KSP) task for the given [sourceSet] depend on - * the [LaunchSpineCompiler] task, so that the Compiler runs before the generated code - * is processed by KSP. - * - * Does nothing if the [LaunchSpineCompiler] task was not created for the [sourceSet], - * or if the KSP task is not present in the project. + * Makes the tasks processing the code of the given [sourceSet] depend on + * the [launchTask], so that the Compiler runs before them. * - * This function must be called after the project is evaluated because the KSP task is - * not yet registered by the time the Compiler plugin is applied. The dependencies of - * the compilation tasks are arranged earlier, when the [LaunchSpineCompiler] task is - * configured. + * These are the Java and Kotlin compilation tasks, and the Kotlin Symbol + * Processing (KSP) task. * - * @see [LaunchSpineCompiler.setDependencies][io.spine.tools.compiler.gradle.plugin.setDependencies] + * The tasks are matched by name and configured once Gradle creates them, so this + * call creates no tasks. The match also covers the tasks registered after this call, + * such as the KSP task, which the KSP plugin registers after the Compiler plugin + * is applied. */ -private fun Project.arrangeKspTaskDependency(sourceSet: SourceSet) { - val launchTask = CompilerTask.find(this, sourceSet) ?: return - val kspTaskName = KspTaskName.of(sourceSet).value() - tasks.findByName(kspTaskName)?.dependsOn(launchTask) +private fun Project.makeCodeTasksDependOn( + launchTask: TaskProvider, + sourceSet: SourceSet +) { + val dependents = setOf( + sourceSet.compileJavaTaskName, + sourceSet.getCompileTaskName(Kotlin.name), + KspTaskName.of(sourceSet).value() + ) + tasks.named { it in dependents }.configureEach { + it.dependsOn(launchTask) + } } /** * Creates [LaunchSpineCompiler] to serve the given [sourceSet]. */ -@CanIgnoreReturnValue private fun Project.createLaunchTask( sourceSet: SourceSet, ): TaskProvider { @@ -290,10 +285,13 @@ private fun Project.createLaunchTask( /** * Creates a task that deletes the files generated for the given [sourceSet]. * - * Makes the `clean` task depend on the created task, and orders the task that - * launches the Compiler CLI to run after it when both are scheduled. + * Makes the `clean` task depend on the created task, and orders the [launchTask] + * to run after it when both are scheduled. */ -private fun Project.createCleanTask(sourceSet: SourceSet) { +private fun Project.createCleanTask( + sourceSet: SourceSet, + launchTask: TaskProvider +) { val cleanSourceSet = SpineCompilerCleanTask.nameFor(sourceSet) val spineCompilerCleanTask = tasks.register(cleanSourceSet) { group = SpineTaskGroup.name @@ -306,7 +304,7 @@ private fun Project.createCleanTask(sourceSet: SourceSet) { tasks.named("clean") { it.dependsOn(spineCompilerCleanTask) } - tasks.named(CompilerTask.nameFor(sourceSet)) { + launchTask.configure { it.mustRunAfter(spineCompilerCleanTask) } } @@ -440,9 +438,20 @@ context(_: GeneratedDirectoryContext) private fun Project.configureGenerateProtoTasks() { protobufExtension?.apply { /* The below block adds a configuration action for the `GenerateProtoTaskCollection`. - We cannot do it like `generateProtoTasks.all().forEach { ... }` because it - breaks the configuration order of the `GenerateProtoTaskCollection`. - This, in turn, leads to missing generated sources in the `compileJava` task. */ + We cannot call `generateProtoTasks.all().forEach { ... }` outside the block + because it breaks the configuration order of the `GenerateProtoTaskCollection`. + This, in turn, leads to missing generated sources in the `compileJava` task. + + Inside the block, the tasks are configured right away rather than via `configureEach`. + Configuring a task rewrites the source directories of its source set + (see `configureSourceSetDirs()`). That must happen before the Protobuf Gradle + Plugin passes the source directories to the IDEA plugin, right after running + this block. Otherwise, reading the directories makes Gradle create the task, + and the rewrite fails the iteration over them with + `ConcurrentModificationException`. The Protobuf Gradle Plugin creates + the tasks at that point anyway when the IDEA plugin is applied. + + The list is copied so that the configuration does not iterate a live collection. */ generateProtoTasks { val all = ImmutableList.copyOf(it.all()) all.forEach { task -> @@ -456,10 +465,13 @@ private fun Project.configureGenerateProtoTasks() { * Configures the given [task] by enabling Kotlin code generation and adding and * configuring the Compiler `protoc` plugin for the task. * - * The function also handles the exclusion of duplicated source code and task dependencies. + * The function also handles the exclusion of duplicated source code. + * + * The dependency of the [LaunchSpineCompiler] task on the given [task] is arranged + * by the [LaunchSpineCompiler] task itself. * * @see [GenerateProtoTask.configureSourceSetDirs] - * @see [Project.handleLaunchTaskDependency] + * @see [LaunchSpineCompiler.consumeProtoFrom] */ context(_: GeneratedDirectoryContext) private fun Project.configureProtoTask(task: GenerateProtoTask) { @@ -468,7 +480,6 @@ private fun Project.configureProtoTask(task: GenerateProtoTask) { } task.addProtocPlugin() task.configureSourceSetDirs() - handleLaunchTaskDependency(task) } private fun GenerateProtoTask.addProtocPlugin() { @@ -516,35 +527,3 @@ private fun GenerateProtoTask.declareRequestFileOutputs(requestFile: File) { outputs.file(requestFile.replaceExtension(Format.ProtoJson.extension)) .withPropertyName(REQUEST_FILE_JSON_PROPERTY) } - -/** - * Makes a [LaunchSpineCompiler], if it exists for the source set of the given [GenerateProtoTask], - * depend on the given [generateProto] task and consume the proto source directories it compiles. - * - * If the [LaunchSpineCompiler] task does not exist (which may be the case for custom source sets - * created by other plugins), arranges the task creation on [Project.afterEvaluate]. - * In this case the [SpineCompilerCleanTask] is also created with appropriate dependencies. - * - * @see [consumeProtoFrom] - */ -private fun Project.handleLaunchTaskDependency(generateProto: GenerateProtoTask) { - val sourceSet = generateProto.sourceSet - val launchTask = CompilerTask.find(this, sourceSet) - check(launchTask is LaunchSpineCompiler?) { - "The task `${launchTask?.path}` is expected to be an instance of" + - " `${LaunchSpineCompiler::class.qualifiedName}`," + - " but was `${launchTask?.javaClass?.name}`." - } - if (launchTask != null) { - launchTask.consumeProtoFrom(generateProto) - } else { - afterEvaluate { - val newTask = createLaunchTask(sourceSet) - newTask.configure { - it.consumeProtoFrom(generateProto) - } - createCleanTask(sourceSet) - arrangeKspTaskDependency(sourceSet) - } - } -} diff --git a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ProjectConfigSpec.kt b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ProjectConfigSpec.kt index 5e57003dd9..93ddda5af5 100644 --- a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ProjectConfigSpec.kt +++ b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ProjectConfigSpec.kt @@ -1,27 +1,15 @@ /* - * Copyright 2025, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. */ package io.spine.tools.compiler.gradle.plugin @@ -100,7 +88,7 @@ class ProjectConfigSpec { @Test fun `bind 'launchSpineCompiler' to Java compilation`() { val task = project.tasks.getByName("compileJava") - assertThat(task.dependsOn) + assertThat(task.taskDependencies.getDependencies(task)) .comparingElementsUsing(taskNames) .contains(CompilerTaskName(SourceSetName.main).value()) } diff --git a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/TaskWiringSpec.kt b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/TaskWiringSpec.kt new file mode 100644 index 0000000000..a0ce042315 --- /dev/null +++ b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/TaskWiringSpec.kt @@ -0,0 +1,266 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.tools.compiler.gradle.plugin + +import com.google.protobuf.gradle.GenerateProtoTask +import com.google.protobuf.gradle.ProtobufPlugin +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.collections.shouldContainAll +import io.kotest.matchers.collections.shouldNotContainAnyOf +import io.kotest.matchers.shouldBe +import io.spine.tools.code.SourceSetName +import io.spine.tools.compiler.gradle.api.CompilerTaskName +import io.spine.tools.compiler.gradle.api.Names.SPINE_COMPILER_PROTOC_PLUGIN +import io.spine.tools.compiler.gradle.api.SpineCompilerCleanTask +import io.spine.tools.compiler.gradle.api.builtins +import io.spine.tools.gradle.project.sourceSets +import java.io.File +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.internal.project.ProjectInternal +import org.gradle.api.tasks.TaskProvider +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.kotlin.dsl.apply +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * Verifies that the plugin arranges the dependencies between the tasks without making + * Gradle create them while the project is configured. + * + * Each test records the names of the tasks Gradle creates, starting before + * the plugins are applied. See [issue #98](https://github.com/SpineEventEngine/compiler/issues/98). + * + * The end-to-end counterpart, which also covers the Kotlin and KSP tasks of + * the real plugins, is `PluginSpec` in the `functionalTest` suite. + */ +@DisplayName("The plugin should") +internal class TaskWiringSpec { + + private lateinit var projectDir: File + private lateinit var project: Project + + /** + * The names of the tasks created by Gradle, in the order of creation. + */ + private val created = mutableListOf() + + private val launchMain = CompilerTaskName(SourceSetName.main).value() + private val launchTest = CompilerTaskName(SourceSetName.test).value() + + @BeforeEach + fun createProject(@TempDir projectDir: File) { + this.projectDir = projectDir + project = ProjectBuilder.builder() + .withProjectDir(projectDir) + .build() + project.group = "io.spine.stubs" + project.tasks.configureEach { + created.add(it.name) + } + with(project) { + apply(plugin = "java") + apply() + apply() + repositories.mavenLocal() + } + } + + private fun evaluate() = (project as ProjectInternal).evaluate() + + /** + * Obtains the names of the tasks on which the task with the given [name] depends. + * + * Creates the task. + */ + private fun dependenciesOf(name: String): List { + val task = project.tasks.getByName(name) + return task.taskDependencies.getDependencies(task).map { it.name } + } + + /** + * Obtains the names of the tasks passed to `dependsOn()` of the task with + * the given [name], as tasks or task providers. + * + * Unlike [dependenciesOf], does not resolve other dependencies, such as + * the build dependencies of the configurations, which would require + * the Compiler artifacts in Maven Local. + */ + private fun declaredDependenciesOf(name: String): List = + project.tasks.getByName(name).dependsOn.mapNotNull { + when (it) { + is Task -> it.name + is TaskProvider<*> -> it.name + else -> null + } + } + + @Test + fun `not create the launch and compilation tasks at configuration time`() { + // Registered before the project is evaluated, like the KSP plugin does. + project.tasks.register("kspKotlin") + + evaluate() + + created shouldNotContainAnyOf listOf( + launchMain, + launchTest, + "compileJava", + "compileTestJava", + "kspKotlin", + ) + } + + @Test + fun `make Java compilation depend on the launch task`() { + evaluate() + + dependenciesOf("compileJava") shouldContain launchMain + dependenciesOf("compileTestJava") shouldContain launchTest + } + + @Test + fun `make Kotlin compilation depend on the launch task`() { + evaluate() + // Stubs of the tasks registered by the Kotlin Gradle Plugin. They are registered + // after the evaluation, so that the plugin does not configure the project for + // Kotlin, which this project does not have. + project.tasks.register("compileKotlin") + project.tasks.register("compileTestKotlin") + + dependenciesOf("compileKotlin") shouldContain launchMain + dependenciesOf("compileTestKotlin") shouldContain launchTest + } + + @Test + fun `make the launch task depend on the 'generateProto' task`() { + evaluate() + + declaredDependenciesOf(launchMain) shouldContain "generateProto" + declaredDependenciesOf(launchTest) shouldContain "generateTestProto" + } + + @Test + fun `pass the proto files compiled by 'generateProto' to the launch task`() { + val protoFile = projectDir.resolve("src/main/proto/given.proto").canonicalFile + protoFile.parentFile.mkdirs() + protoFile.writeText("syntax = \"proto3\";") + + evaluate() + + val launchTask = project.tasks.getByName(launchMain) as LaunchSpineCompiler + launchTask.protoSourceDirs.asFileTree.files shouldContain protoFile + } + + @Test + fun `make 'clean' depend on the clean tasks, which the launch tasks must run after`() { + evaluate() + + val cleanMain = SpineCompilerCleanTask.nameFor(project.sourceSets.getByName("main")) + val cleanTest = SpineCompilerCleanTask.nameFor(project.sourceSets.getByName("test")) + dependenciesOf("clean") shouldContainAll listOf(cleanMain, cleanTest) + val launchTask = project.tasks.getByName(launchMain) + launchTask.mustRunAfter.getDependencies(launchTask).map { it.name } shouldContain cleanMain + } + + @Test + fun `make the KSP tasks depend on the launch task, even if registered later`() { + project.tasks.register("kspKotlin") + evaluate() + // Registered after the project is evaluated, which no `afterEvaluate` could serve. + project.tasks.register("kspTestKotlin") + + dependenciesOf("kspKotlin") shouldContain launchMain + dependenciesOf("kspTestKotlin") shouldContain launchTest + } + + @Test + fun `serve a source set added after the plugin is applied`() { + val sourceSet = project.sourceSets.create("integrationTest") + val launchTask = CompilerTaskName(SourceSetName(sourceSet.name)).value() + + evaluate() + + created shouldNotContainAnyOf listOf(launchTask, sourceSet.compileJavaTaskName) + project.tasks.names shouldContain launchTask + dependenciesOf("clean") shouldContain SpineCompilerCleanTask.nameFor(sourceSet) + dependenciesOf(sourceSet.compileJavaTaskName) shouldContain launchTask + declaredDependenciesOf(launchTask) shouldContain "generateIntegrationTestProto" + } + + /** + * Verifies that the configuration action the plugin adds for each [GenerateProtoTask] + * runs before the Protobuf Gradle Plugin finalizes the task, and that the code + * generated by the Compiler reaches the `compileJava` task. + * + * The action adds the Compiler `protoc` plugin and the `kotlin` built-in to the task. + * Once the task is finalized, the Protobuf Gradle Plugin rejects such changes, and + * the project would fail to evaluate. The action also adds the directory with + * the code generated by the Compiler to the source set. + */ + @Test + fun `configure 'generateProto' before it is finalized`() { + // The temporary directory may be reached via a symbolic link, as `/var` on macOS. + // The compilation sources are resolved to canonical paths. + val generatedFile = projectDir.resolve("generated/main/java/Generated.java") + .canonicalFile + generatedFile.parentFile.mkdirs() + generatedFile.writeText("class Generated {}") + + evaluate() + + val generateProto = project.tasks.getByName("generateProto") as GenerateProtoTask + generateProto.hasPlugin(SPINE_COMPILER_PROTOC_PLUGIN) shouldBe true + generateProto.builtins() shouldContain "kotlin" + val compileJava = project.tasks.getByName("compileJava") as JavaCompile + compileJava.source.files shouldContain generatedFile + } + + /** + * Verifies that the source set directories are configured before the Protobuf Gradle + * Plugin passes them to the IDEA plugin, after running the `generateProtoTasks { }` + * blocks. + * + * The configuration of each [GenerateProtoTask] rewrites the source directories of + * its source set. If it ran only once Gradle creates the task, the IDEA plugin reading + * the source directories would make Gradle create the task, and the project would fail + * to evaluate with `ConcurrentModificationException`. + */ + @Test + fun `configure 'generateProto' before the IDEA plugin reads the source set`() { + project.pluginManager.apply("idea") + + evaluate() + + val generateProto = project.tasks.getByName("generateProto") as GenerateProtoTask + generateProto.hasPlugin(SPINE_COMPILER_PROTOC_PLUGIN) shouldBe true + } + + @Test + fun `configure 'generateProto' created before the project is evaluated`() { + // A build script may create the task before the Protobuf Gradle Plugin + // runs the `generateProtoTasks { }` blocks. + project.tasks.getByName("generateProto") + + evaluate() + + val generateProto = project.tasks.getByName("generateProto") as GenerateProtoTask + generateProto.hasPlugin(SPINE_COMPILER_PROTOC_PLUGIN) shouldBe true + dependenciesOf("compileJava") shouldContain launchMain + } +} From c34cd3112265b0c78b88c7799e51bc30bfe1d3ef Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 18:18:46 +0000 Subject: [PATCH 03/14] Make `ExcludeProtocOutputSpec` able to fail The spec passed with the `protoc` output filter of `compileJava` disabled: - The directory was added to the source set before the evaluation, and the plugin removes it from the source set then, so the task filter had nothing to filter. The directory is now re-added after the evaluation. - The leaked directory was added via the `@TempDir` path, which goes through the `/var` symbolic link on macOS, so the file was reported under a path that differs from the asserted one. The paths now come from `project.projectDir`. The assertions inspect the `files` of the task source, with a positive control for a hand-written file. Co-Authored-By: Claude Opus 5.5 --- .../gradle/plugin/ExcludeProtocOutputSpec.kt | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ExcludeProtocOutputSpec.kt b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ExcludeProtocOutputSpec.kt index 52e77aff11..188e84016f 100644 --- a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ExcludeProtocOutputSpec.kt +++ b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ExcludeProtocOutputSpec.kt @@ -1,33 +1,22 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. */ package io.spine.tools.compiler.gradle.plugin import com.google.protobuf.gradle.ProtobufPlugin -import io.kotest.matchers.shouldBe +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.collections.shouldNotContain import java.io.File import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.tasks.SourceSetContainer @@ -46,10 +35,20 @@ internal class ExcludeProtocOutputSpec { * source directories of the `main` source set, and verifies that the file it * contains does not reach the `compileJava` task — see * [issue #19](https://github.com/SpineEventEngine/compiler/issues/19). + * + * The directory is added after the project is evaluated: the plugin removes it + * from the source set during the evaluation, so a directory added earlier would + * not reach the task even without the filter applied to the task itself. + * + * The paths are resolved against [Project.getProjectDir][org.gradle.api.Project.getProjectDir], + * which Gradle canonicalizes, rather than against the given temporary directory, + * which may be reached via a symbolic link, such as `/var` on macOS. Otherwise, + * the paths of the same file may differ, and the assertions pass whatever the task + * source contains. */ @Test - fun `keeping it out of the Java compile task source`(@TempDir projectDir: File) { - val project = ProjectBuilder.builder().withProjectDir(projectDir).build() + fun `keeping it out of the Java compile task source`(@TempDir tempDir: File) { + val project = ProjectBuilder.builder().withProjectDir(tempDir).build() project.group = "io.spine.stubs" with(project) { apply(plugin = "java") @@ -57,19 +56,29 @@ internal class ExcludeProtocOutputSpec { apply() repositories.mavenLocal() } + val projectDir = project.projectDir - // A file under the default `protoc` output directory, added to the source set - // as if the source-set-level deduplication had not removed it. + // A file under the default `protoc` output directory. val protocJavaDir = projectDir.resolve("build/generated/sources/proto/main/java") protocJavaDir.mkdirs() val leaked = protocJavaDir.resolve("Leaked.java") leaked.writeText("class Leaked {}") - val sourceSets = project.extensions.getByType(SourceSetContainer::class.java) - sourceSets.getByName("main").java.srcDir(protocJavaDir) + + // A hand-written file, which must reach the task. + val handWritten = projectDir.resolve("src/main/java/HandWritten.java") + handWritten.parentFile.mkdirs() + handWritten.writeText("class HandWritten {}") (project as ProjectInternal).evaluate() + // Re-add the `protoc` output directory after the plugin removed it from + // the source set during the evaluation, as another plugin may do. + val sourceSets = project.extensions.getByType(SourceSetContainer::class.java) + sourceSets.getByName("main").java.srcDir(protocJavaDir) + val compileJava = project.tasks.getByName("compileJava") as JavaCompile - compileJava.source.contains(leaked) shouldBe false + val sources = compileJava.source.files + sources shouldContain handWritten + sources shouldNotContain leaked } } From 6416e1ee9f2affd022bd140c41f75a7ad0a1327d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 18:18:53 +0000 Subject: [PATCH 04/14] Update dependency reports Co-Authored-By: Claude Opus 5.5 --- docs/dependencies/dependencies.md | 44 +++++++++++++++---------------- docs/dependencies/pom.xml | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index f3b1f99ca8..7b00c65f37 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine.tools:compiler-api:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-api:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -1860,14 +1860,14 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:39 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-api-tests:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-api-tests:2.0.0-SNAPSHOT.082` ## Runtime ## Compile, tests, and tooling @@ -2578,14 +2578,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:38 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-backend:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-backend:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -4449,14 +4449,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:39 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-cli:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-cli:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -6528,14 +6528,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:39 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-gradle-api:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-gradle-api:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -8277,14 +8277,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:38 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-gradle-plugin:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-gradle-plugin:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -10066,14 +10066,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:39 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-jvm:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-jvm:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -12003,14 +12003,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:39 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-params:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-params:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -13862,14 +13862,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:39 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-protoc-plugin:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-protoc-plugin:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -14764,14 +14764,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:38 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-test-env:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-test-env:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -16611,14 +16611,14 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:39 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.tools:compiler-testlib:2.0.0-SNAPSHOT.081` +# Dependencies of `io.spine.tools:compiler-testlib:2.0.0-SNAPSHOT.082` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -18583,6 +18583,6 @@ This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 22 15:15:27 WEST 2026** using +This report was generated on **Thu Oct 29 17:27:39 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index d5ccfdcf7f..a10f0dcea9 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject. --> io.spine.tools compiler -2.0.0-SNAPSHOT.081 +2.0.0-SNAPSHOT.082 2015 From f2b063f27072b741e0c20cbdb9d2e47804072018 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 18:27:44 +0000 Subject: [PATCH 05/14] Address pre-PR review of the lazy task wiring - Cover a build that makes Gradle create each task as soon as it is registered, and document the registration order the launch task relies on to find its `generate*Proto` task. - Make `consumeProtoFrom()` private and look the task up with the reified `named()`. - Pass the source set first to both helpers of `createTasks()`. - Fix the wording of the KDoc and comments, including the `find()` return description, and document `UnknownTaskException` thrown by `get()`. Co-Authored-By: Claude Opus 5.5 --- .agents/tasks/lazy-task-wiring.md | 3 + .../tools/compiler/gradle/api/TaskLocator.kt | 11 ++-- .../compiler/gradle/api/TaskLocatorSpec.kt | 11 ++-- .../gradle/plugin/LaunchSpineCompiler.kt | 12 +++- .../tools/compiler/gradle/plugin/Plugin.kt | 30 +++++---- .../gradle/plugin/ExcludeProtocOutputSpec.kt | 8 +-- .../compiler/gradle/plugin/TaskWiringSpec.kt | 62 ++++++++++++++----- 7 files changed, 90 insertions(+), 47 deletions(-) diff --git a/.agents/tasks/lazy-task-wiring.md b/.agents/tasks/lazy-task-wiring.md index b309ff075e..baf7b1a679 100644 --- a/.agents/tasks/lazy-task-wiring.md +++ b/.agents/tasks/lazy-task-wiring.md @@ -56,3 +56,6 @@ as they are. `protoSourceDirs` contents, and the Kotlin compile task; `createCleanTask()` takes the launch task provider. Not staged for commit: the version bump and dependency reports (separate commits per the version policy). +- 2026-10-29 — pre-PR review (`spine-code-review`, `kotlin-engineer`, `review-docs`): no + Must-fix. Added a test creating each task as soon as it is registered, made + `consumeProtoFrom()` private, and fixed KDoc wording. diff --git a/gradle-api/src/main/kotlin/io/spine/tools/compiler/gradle/api/TaskLocator.kt b/gradle-api/src/main/kotlin/io/spine/tools/compiler/gradle/api/TaskLocator.kt index b8a5cf5fa8..f0a61a96bd 100644 --- a/gradle-api/src/main/kotlin/io/spine/tools/compiler/gradle/api/TaskLocator.kt +++ b/gradle-api/src/main/kotlin/io/spine/tools/compiler/gradle/api/TaskLocator.kt @@ -23,7 +23,7 @@ import org.gradle.api.tasks.TaskProvider * Abstract base for utilities finding tasks of a certain type by * the [provided name pattern][nameFor]. * - * The [exists] and [named] functions do not make Gradle create a task registered + * The [exists] and [named] functions do not make Gradle create a task that is registered * but not yet created. Prefer them to [find] and [get] during the configuration phase. */ public abstract class TaskLocator { @@ -38,6 +38,7 @@ public abstract class TaskLocator { * * Creates the task if it is registered but not yet created. * + * @throws org.gradle.api.UnknownTaskException if there is no task for this source set * @see named */ public fun get(project: Project, sourceSet: SourceSet): Task { @@ -50,7 +51,7 @@ public abstract class TaskLocator { * * Creates the task if it is registered but not yet created. * - * @return the task or `null` if there is no task created for this source set + * @return the task or `null` if there is no task for this source set * @see exists */ public fun find(project: Project, sourceSet: SourceSet): Task? { @@ -61,7 +62,8 @@ public abstract class TaskLocator { /** * Tells if the given project has the task for the specified source set. * - * Unlike [find], does not create the task if it is registered but not yet created. + * Unlike [find], this function does not create the task if it is registered + * but not yet created. */ public fun exists(project: Project, sourceSet: SourceSet): Boolean = nameFor(sourceSet) in project.tasks.names @@ -69,7 +71,8 @@ public abstract class TaskLocator { /** * Obtains a provider of the task in the given project for the specified source set. * - * Unlike [get], does not create the task if it is registered but not yet created. + * Unlike [get], this function does not create the task if it is registered + * but not yet created. * * @throws org.gradle.api.UnknownTaskException if there is no task for this source set */ diff --git a/gradle-api/src/test/kotlin/io/spine/tools/compiler/gradle/api/TaskLocatorSpec.kt b/gradle-api/src/test/kotlin/io/spine/tools/compiler/gradle/api/TaskLocatorSpec.kt index fa075de145..4a65e0a533 100644 --- a/gradle-api/src/test/kotlin/io/spine/tools/compiler/gradle/api/TaskLocatorSpec.kt +++ b/gradle-api/src/test/kotlin/io/spine/tools/compiler/gradle/api/TaskLocatorSpec.kt @@ -49,8 +49,7 @@ internal class TaskLocatorSpec { private val cleanTask = project.tasks.register(SpineCompilerCleanTask.nameFor(main)) /** - * The names of the tasks that Gradle created after the [launchTask] and - * the [cleanTask] were registered. + * The names of the [launchTask] and the [cleanTask], recorded when Gradle creates them. */ private val created = mutableListOf().also { names -> project.tasks.named { it == launchTask.name || it == cleanTask.name } @@ -107,12 +106,12 @@ internal class TaskLocatorSpec { @Test fun `provide a task without creating it`() { - val launchTaskProvider = CompilerTask.named(project, main) - val cleanTaskProvider = SpineCompilerCleanTask.named(project, main) + val namedLaunchTask = CompilerTask.named(project, main) + val namedCleanTask = SpineCompilerCleanTask.named(project, main) created.shouldBeEmpty() - launchTaskProvider.get() shouldBeSameInstanceAs launchTask.get() - cleanTaskProvider.get() shouldBeSameInstanceAs cleanTask.get() + namedLaunchTask.get() shouldBeSameInstanceAs launchTask.get() + namedCleanTask.get() shouldBeSameInstanceAs cleanTask.get() } @Test diff --git a/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt b/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt index ea7c46712f..19ed3222ba 100644 --- a/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt +++ b/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/LaunchSpineCompiler.kt @@ -55,6 +55,7 @@ import org.gradle.api.tasks.PathSensitive import org.gradle.api.tasks.PathSensitivity import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.TaskProvider +import org.gradle.kotlin.dsl.named import org.gradle.process.CommandLineArgumentProvider /** @@ -311,7 +312,12 @@ internal fun LaunchSpineCompiler.applyDefaults(sourceSet: SourceSet) { * Makes this task depend on the build of the configurations used to run the Compiler, * and on the [GenerateProtoTask] of the given [sourceSet], if the project has one. * - * The dependencies of other tasks on this task are arranged when this task is registered. + * The [GenerateProtoTask] is registered by the time Gradle creates this task: + * the Protobuf Gradle Plugin, which must be applied before the Compiler plugin, + * registers it once the source set is added, before the Compiler plugin registers + * this task. + * + * The plugin makes other tasks depend on this task right after registering it. * * @see [Project.makeCodeTasksDependOn][io.spine.tools.compiler.gradle.plugin.makeCodeTasksDependOn] */ @@ -323,7 +329,7 @@ private fun LaunchSpineCompiler.setDependencies(sourceSet: SourceSet) { ) val generateProtoName = ProtobufTaskName.generateProto(SourceSetName(sourceSet.name)).value() if (generateProtoName in project.tasks.names) { - consumeProtoFrom(project.tasks.named(generateProtoName, GenerateProtoTask::class.java)) + consumeProtoFrom(project.tasks.named(generateProtoName)) } } @@ -339,7 +345,7 @@ private fun LaunchSpineCompiler.setDependencies(sourceSet: SourceSet) { * * The call does not make Gradle create the [generateProto] task. */ -internal fun LaunchSpineCompiler.consumeProtoFrom(generateProto: TaskProvider) { +private fun LaunchSpineCompiler.consumeProtoFrom(generateProto: TaskProvider) { dependsOn(generateProto) protoSourceDirs.from(generateProto.map { it.sourceDirs }) } diff --git a/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/Plugin.kt b/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/Plugin.kt index 95c480d96c..96fa2468e5 100644 --- a/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/Plugin.kt +++ b/gradle-plugin/src/main/kotlin/io/spine/tools/compiler/gradle/plugin/Plugin.kt @@ -225,10 +225,10 @@ private fun Project.requireProtobufRuntimeOf(source: Configuration, target: Conf } /** - * Creates the [SpineCompilerCleanTask] and [LaunchSpineCompiler] tasks for each source set + * Registers the [SpineCompilerCleanTask] and [LaunchSpineCompiler] tasks for each source set * of this project, including the source sets added by other plugins after this call. * - * The tasks are registered, not created. Arranging the dependencies on + * Gradle creates none of the tasks by this call. Making other tasks depend on * the [LaunchSpineCompiler] tasks creates no tasks either. * * @see [Project.makeCodeTasksDependOn] @@ -236,7 +236,7 @@ private fun Project.requireProtobufRuntimeOf(source: Configuration, target: Conf private fun Project.createTasks() { sourceSets.configureEach { sourceSet -> val launchTask = createLaunchTask(sourceSet) - makeCodeTasksDependOn(launchTask, sourceSet) + makeCodeTasksDependOn(sourceSet, launchTask) createCleanTask(sourceSet, launchTask) } } @@ -245,17 +245,15 @@ private fun Project.createTasks() { * Makes the tasks processing the code of the given [sourceSet] depend on * the [launchTask], so that the Compiler runs before them. * - * These are the Java and Kotlin compilation tasks, and the Kotlin Symbol - * Processing (KSP) task. + * These are the Java and Kotlin compilation tasks and the Kotlin Symbol Processing (KSP) task. * - * The tasks are matched by name and configured once Gradle creates them, so this - * call creates no tasks. The match also covers the tasks registered after this call, - * such as the KSP task, which the KSP plugin registers after the Compiler plugin - * is applied. + * The tasks are matched by name and configured once Gradle creates them, so this call + * creates no tasks. The match also covers the tasks registered after this call, such as + * the KSP task, which the KSP plugin registers after the Compiler plugin is applied. */ private fun Project.makeCodeTasksDependOn( + sourceSet: SourceSet, launchTask: TaskProvider, - sourceSet: SourceSet ) { val dependents = setOf( sourceSet.compileJavaTaskName, @@ -290,7 +288,7 @@ private fun Project.createLaunchTask( */ private fun Project.createCleanTask( sourceSet: SourceSet, - launchTask: TaskProvider + launchTask: TaskProvider, ) { val cleanSourceSet = SpineCompilerCleanTask.nameFor(sourceSet) val spineCompilerCleanTask = tasks.register(cleanSourceSet) { @@ -447,11 +445,12 @@ private fun Project.configureGenerateProtoTasks() { (see `configureSourceSetDirs()`). That must happen before the Protobuf Gradle Plugin passes the source directories to the IDEA plugin, right after running this block. Otherwise, reading the directories makes Gradle create the task, - and the rewrite fails the iteration over them with - `ConcurrentModificationException`. The Protobuf Gradle Plugin creates - the tasks at that point anyway when the IDEA plugin is applied. + and the rewrite breaks the iteration over the directories with + `ConcurrentModificationException`. If the IDEA plugin is applied, the Protobuf + Gradle Plugin creates the tasks at that point anyway. - The list is copied so that the configuration does not iterate a live collection. */ + The result of `all()` is copied so that configuring the tasks does not iterate + over a live collection. */ generateProtoTasks { val all = ImmutableList.copyOf(it.all()) all.forEach { task -> @@ -471,7 +470,6 @@ private fun Project.configureGenerateProtoTasks() { * by the [LaunchSpineCompiler] task itself. * * @see [GenerateProtoTask.configureSourceSetDirs] - * @see [LaunchSpineCompiler.consumeProtoFrom] */ context(_: GeneratedDirectoryContext) private fun Project.configureProtoTask(task: GenerateProtoTask) { diff --git a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ExcludeProtocOutputSpec.kt b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ExcludeProtocOutputSpec.kt index 188e84016f..8d2f62f06f 100644 --- a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ExcludeProtocOutputSpec.kt +++ b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/ExcludeProtocOutputSpec.kt @@ -40,11 +40,11 @@ internal class ExcludeProtocOutputSpec { * from the source set during the evaluation, so a directory added earlier would * not reach the task even without the filter applied to the task itself. * - * The paths are resolved against [Project.getProjectDir][org.gradle.api.Project.getProjectDir], + * The paths are resolved against [Project.projectDir][org.gradle.api.Project.getProjectDir], * which Gradle canonicalizes, rather than against the given temporary directory, - * which may be reached via a symbolic link, such as `/var` on macOS. Otherwise, - * the paths of the same file may differ, and the assertions pass whatever the task - * source contains. + * which may be reached via a symbolic link, such as `/var` on macOS. Otherwise, the + * paths of the same file may differ, and `shouldNotContain` would pass whatever the + * task source contains. */ @Test fun `keeping it out of the Java compile task source`(@TempDir tempDir: File) { diff --git a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/TaskWiringSpec.kt b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/TaskWiringSpec.kt index a0ce042315..25c6fccf94 100644 --- a/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/TaskWiringSpec.kt +++ b/gradle-plugin/src/test/kotlin/io/spine/tools/compiler/gradle/plugin/TaskWiringSpec.kt @@ -46,8 +46,8 @@ import org.junit.jupiter.api.io.TempDir * Each test records the names of the tasks Gradle creates, starting before * the plugins are applied. See [issue #98](https://github.com/SpineEventEngine/compiler/issues/98). * - * The end-to-end counterpart, which also covers the Kotlin and KSP tasks of - * the real plugins, is `PluginSpec` in the `functionalTest` suite. + * The end-to-end counterpart, which also covers the Kotlin and Kotlin Symbol Processing (KSP) + * tasks of the real plugins, is `PluginSpec` in the `functionalTest` suite. */ @DisplayName("The plugin should") internal class TaskWiringSpec { @@ -88,7 +88,7 @@ internal class TaskWiringSpec { * * Creates the task. */ - private fun dependenciesOf(name: String): List { + private fun dependenciesOf(name: String, project: Project = this.project): List { val task = project.tasks.getByName(name) return task.taskDependencies.getDependencies(task).map { it.name } } @@ -97,11 +97,11 @@ internal class TaskWiringSpec { * Obtains the names of the tasks passed to `dependsOn()` of the task with * the given [name], as tasks or task providers. * - * Unlike [dependenciesOf], does not resolve other dependencies, such as - * the build dependencies of the configurations, which would require + * Unlike [dependenciesOf], this function does not resolve other dependencies, + * such as the build dependencies of the configurations, which would require * the Compiler artifacts in Maven Local. */ - private fun declaredDependenciesOf(name: String): List = + private fun declaredDependenciesOf(name: String, project: Project = this.project) = project.tasks.getByName(name).dependsOn.mapNotNull { when (it) { is Task -> it.name @@ -138,8 +138,8 @@ internal class TaskWiringSpec { fun `make Kotlin compilation depend on the launch task`() { evaluate() // Stubs of the tasks registered by the Kotlin Gradle Plugin. They are registered - // after the evaluation, so that the plugin does not configure the project for - // Kotlin, which this project does not have. + // after the evaluation, so that the Compiler plugin does not configure the project + // for Kotlin, which this project does not have. project.tasks.register("compileKotlin") project.tasks.register("compileTestKotlin") @@ -182,7 +182,8 @@ internal class TaskWiringSpec { fun `make the KSP tasks depend on the launch task, even if registered later`() { project.tasks.register("kspKotlin") evaluate() - // Registered after the project is evaluated, which no `afterEvaluate` could serve. + // Registered after the project is evaluated, a case that an `afterEvaluate` + // callback could not handle. project.tasks.register("kspTestKotlin") dependenciesOf("kspKotlin") shouldContain launchMain @@ -210,12 +211,12 @@ internal class TaskWiringSpec { * * The action adds the Compiler `protoc` plugin and the `kotlin` built-in to the task. * Once the task is finalized, the Protobuf Gradle Plugin rejects such changes, and - * the project would fail to evaluate. The action also adds the directory with + * the project fails to evaluate. The action also adds the directory with * the code generated by the Compiler to the source set. */ @Test fun `configure 'generateProto' before it is finalized`() { - // The temporary directory may be reached via a symbolic link, as `/var` on macOS. + // The temporary directory may be reached via a symbolic link, such as `/var` on macOS. // The compilation sources are resolved to canonical paths. val generatedFile = projectDir.resolve("generated/main/java/Generated.java") .canonicalFile @@ -233,11 +234,11 @@ internal class TaskWiringSpec { /** * Verifies that the source set directories are configured before the Protobuf Gradle - * Plugin passes them to the IDEA plugin, after running the `generateProtoTasks { }` - * blocks. + * Plugin passes them to the IDEA plugin, which it does right after running the + * `generateProtoTasks { }` blocks. * * The configuration of each [GenerateProtoTask] rewrites the source directories of - * its source set. If it ran only once Gradle creates the task, the IDEA plugin reading + * its source set. If it ran only when Gradle creates the task, the IDEA plugin reading * the source directories would make Gradle create the task, and the project would fail * to evaluate with `ConcurrentModificationException`. */ @@ -263,4 +264,37 @@ internal class TaskWiringSpec { generateProto.hasPlugin(SPINE_COMPILER_PROTOC_PLUGIN) shouldBe true dependenciesOf("compileJava") shouldContain launchMain } + + /** + * Verifies the wiring when Gradle creates each task as soon as it is registered, + * as it does for a build calling `tasks.all { }` before applying the plugins. + * + * The [LaunchSpineCompiler] task is then configured right when the plugin registers + * it, and finds the `generateProto` task registered by the Protobuf Gradle Plugin. + */ + @Test + fun `wire the tasks created as soon as they are registered`() { + val eager = ProjectBuilder.builder() + .withProjectDir(projectDir.resolve("eager")) + .build() + eager.group = "io.spine.stubs" + // Makes Gradle create each task once it is registered. + eager.tasks.all { } + with(eager) { + apply(plugin = "java") + apply() + apply() + repositories.mavenLocal() + } + val protoFile = eager.projectDir.resolve("src/main/proto/given.proto") + protoFile.parentFile.mkdirs() + protoFile.writeText("syntax = \"proto3\";") + + (eager as ProjectInternal).evaluate() + + declaredDependenciesOf(launchMain, eager) shouldContain "generateProto" + val launchTask = eager.tasks.getByName(launchMain) as LaunchSpineCompiler + launchTask.protoSourceDirs.asFileTree.files shouldContain protoFile + dependenciesOf("compileJava", eager) shouldContain launchMain + } } From dae2620b97d59c48d957c0b0e9f6beace772eecb Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 19:50:55 +0000 Subject: [PATCH 06/14] Update shared agent tooling and config (./config/pull) Co-Authored-By: Claude Opus 5.5 --- .github/workflows/increment-guard.yml | 20 +- .github/workflows/publish-api-docs.yml | 100 +++++ .github/workflows/publish.yml | 2 +- .github/workflows/revalidate-versions.yml | 6 +- buildSrc/src/main/kotlin/BuildExtensions.kt | 24 +- buildSrc/src/main/kotlin/DokkaExts.kt | 25 +- .../src/main/kotlin/dokka-setup.gradle.kts | 7 +- .../kotlin/io/spine/dependency/local/Base.kt | 2 +- .../io/spine/dependency/local/BaseTypes.kt | 2 +- .../io/spine/dependency/local/Change.kt | 2 +- .../io/spine/dependency/local/Compiler.kt | 4 +- .../io/spine/dependency/local/CoreJvm.kt | 2 +- .../spine/dependency/local/CoreJvmCompiler.kt | 4 +- .../io/spine/dependency/local/DokkaTools.kt | 2 +- .../io/spine/dependency/local/Logging.kt | 15 + .../kotlin/io/spine/dependency/local/Time.kt | 2 +- .../io/spine/dependency/local/ToolBase.kt | 16 +- .../io/spine/dependency/local/Validation.kt | 2 +- .../src/main/kotlin/io/spine/gradle/Cli.kt | 41 +- .../io/spine/gradle/ProjectExtensions.kt | 4 + .../main/kotlin/io/spine/gradle/TaskName.kt | 20 + .../gradle/checkstyle/CheckStyleConfig.kt | 2 +- .../kotlin/io/spine/gradle/git/Repository.kt | 130 ++++++- .../spine/gradle/github/pages/AuthorEmail.kt | 3 +- .../gradle/github/pages/DocsPublication.kt | 254 +++++++++++++ .../gradle/github/pages/PublishAllApiDocs.kt | 76 ++++ ...UpdateGitHubPages.kt => PublishApiDocs.kt} | 82 ++-- ...xtension.kt => PublishApiDocsExtension.kt} | 32 +- .../github/pages/RepositoryExtensions.kt | 26 +- .../io/spine/gradle/github/pages/TaskName.kt | 16 +- .../io/spine/gradle/github/pages/Update.kt | 148 -------- .../gradle/javadoc/ExcludeInternalDoclet.kt | 2 +- .../io/spine/gradle/javadoc/JavadocConfig.kt | 36 +- .../io/spine/gradle/publish/ProtoExts.kt | 16 +- .../gradle/publish/PublicationChecksums.kt | 44 +-- .../spine/gradle/publish/PublicationSbom.kt | 2 +- .../spine/gradle/publish/SpinePublishing.kt | 4 + .../publish/StandardJavaPublicationHandler.kt | 68 ++++ .../gradle/report/license/LicenseReporter.kt | 13 +- .../spine/gradle/report/pom/PomGenerator.kt | 6 +- .../src/main/kotlin/jvm-module.gradle.kts | 20 +- buildSrc/src/main/kotlin/module.gradle.kts | 8 +- .../src/test/kotlin/BuildExtensionsSpec.kt | 73 ++++ .../test/kotlin/io/spine/gradle/CliSpec.kt | 51 +++ .../io/spine/gradle/docs/DokkaSetupIgTest.kt | 8 +- .../io/spine/gradle/git/RepositorySpec.kt | 313 ++++++++++++++++ .../gradle/github/pages/NewestAboveSpec.kt | 55 +++ .../github/pages/PublishApiDocsIgTest.kt | 349 ++++++++++++++++++ .../spine/gradle/javadoc/JavadocConfigSpec.kt | 45 +++ .../io/spine/gradle/publish/ProtoExtsSpec.kt | 55 +++ .../gradle/publish/PublicationSbomIgTest.kt | 71 ++++ .../license/DependencyReportOutputTest.kt | 23 ++ config | 2 +- 53 files changed, 1974 insertions(+), 361 deletions(-) create mode 100644 .github/workflows/publish-api-docs.yml create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/github/pages/DocsPublication.kt create mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishAllApiDocs.kt rename buildSrc/src/main/kotlin/io/spine/gradle/github/pages/{UpdateGitHubPages.kt => PublishApiDocs.kt} (65%) rename buildSrc/src/main/kotlin/io/spine/gradle/github/pages/{UpdateGitHubPagesExtension.kt => PublishApiDocsExtension.kt} (70%) delete mode 100644 buildSrc/src/main/kotlin/io/spine/gradle/github/pages/Update.kt create mode 100644 buildSrc/src/test/kotlin/BuildExtensionsSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/CliSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/git/RepositorySpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/github/pages/NewestAboveSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/github/pages/PublishApiDocsIgTest.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/javadoc/JavadocConfigSpec.kt create mode 100644 buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtoExtsSpec.kt diff --git a/.github/workflows/increment-guard.yml b/.github/workflows/increment-guard.yml index 9a6333f0ff..56f3008854 100644 --- a/.github/workflows/increment-guard.yml +++ b/.github/workflows/increment-guard.yml @@ -1,9 +1,13 @@ # Guards the project version by executing the Gradle `checkVersionIncrement` task, # which verifies that the version is both (a) strictly greater than the base branch # version in `version.gradle.kts` and (b) not already published. The result is -# published as the `Version Guard` commit status — the context required by branch -# protection and re-published by `revalidate-versions.yml` on the heads of other open -# PRs when the base branch advances (so a stale duplicate bump turns red before merge). +# published as the `Version bump` commit status, which `revalidate-versions.yml` also +# re-publishes on the heads of other open PRs when the base branch advances (so a stale +# duplicate bump turns red before merge). +# +# Branch protection must require the `Version bump` status, not the job's own +# `Check version increment` check run: only the status carries the revalidation verdict, +# and a job skipped by its `if` reports a passing check run. # # The check runs only for pull requests targeting a default (`master`/`main`) or # a release-line (e.g. `2.x-jdk8-master`) branch. It is the responsibility of a branch @@ -21,7 +25,7 @@ on: pull_request: # Beyond the default activity types (`opened`, `synchronize`, `reopened`), two more are # needed because they change what the guard must compare against without a new head SHA, - # which would otherwise leave a stale-green `Version Guard` status mergeable: + # which would otherwise leave a stale-green `Version bump` status mergeable: # * `ready_for_review` — a draft that went stale while in draft becomes ready; and # * `edited` — the base branch is retargeted (e.g. a release line -> `master`), so the # strict comparison must be recomputed against the new base. @@ -39,7 +43,7 @@ jobs: (endsWith(github.base_ref, 'master') || endsWith(github.base_ref, 'main')) && (github.event.action != 'edited' || github.event.changes.base.ref.from != '') - # `statuses: write` lets the job publish the `Version Guard` commit status that + # `statuses: write` lets the job publish the `Version bump` commit status that # branch protection requires. permissions: contents: read @@ -76,7 +80,7 @@ jobs: VERSION_GUARD: "true" run: ./gradlew checkVersionIncrement --stacktrace - # Publish the verdict as the `Version Guard` commit status on the PR head. Posting it + # Publish the verdict as the `Version bump` commit status on the PR head. Posting it # on every run (success or failure) is what lets a later re-bump clear a failure that # `revalidate-versions.yml` set when the base branch advanced. # @@ -84,7 +88,7 @@ jobs: # posted (and a fork head SHA is not in this repo). The Spine agent workflow pushes PR # branches to the same repository; fork contributions are handled by a maintainer, who # owns the version bump. - - name: Report the Version Guard status + - name: Report the Version bump status if: always() && github.event.pull_request.head.repo.fork == false shell: bash env: @@ -96,5 +100,5 @@ jobs: fi gh api -X POST "repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \ -f state="${state}" \ - -f context="Version Guard" \ + -f context="Version bump" \ -f description="Version increment check" diff --git a/.github/workflows/publish-api-docs.yml b/.github/workflows/publish-api-docs.yml new file mode 100644 index 0000000000..1f6f17a18f --- /dev/null +++ b/.github/workflows/publish-api-docs.yml @@ -0,0 +1,100 @@ +name: Publish API docs + +# Publishes the API documentation of the published modules to the `gh-pages` +# branch, which GitHub Pages serves under `spine.io`. +# +# The job runs apart from `publish.yml`, and neither waits for the other: a +# failure here leaves the Maven publication intact, and the other way round. +# `:publishAllApiDocs` is registered in the root project by `spinePublishing { }`, +# so it exists in every repository that publishes, and does nothing where no +# module documents itself. It runs the `publishApiDocs` task of each published +# module. +# +# Only release versions are published. For a snapshot version, which most merges +# produce, the task of each module only says that it skips the documentation, +# and the run ends green without generating or pushing any. +# +# A failed run can be re-run as it is: each module commits its documentation +# even when nothing changed, and retries a failed push after rebasing onto +# `gh-pages`. +# +# Each module clones only the tip of `gh-pages` and checks out only its own most +# recent documentation and the folder of its version, so that a run does not +# fetch the documentation of every version of every module. +# +# This job does not ask whether `publish.yml` could publish the version, as that +# would couple the two again. When `publish.yml` stops because the version is +# already taken, which the version checks of pull requests normally prevent, +# this job still copies the documentation of the commit over that of the version. +# +# Unlike `publish.yml`, this file is not a caller of a reusable workflow hosted +# by `config`. That split exists to make `config` the signer of the attestation +# of the published artifacts, and the documentation is not attested. + +on: + push: + branches: [master] + +jobs: + publish-api-docs: + name: Publish API docs + runs-on: ubuntu-latest + + # One run at a time per repository, since every run pushes to `gh-pages`. + # `queue: max` keeps up to 100 runs waiting, instead of letting a newer run + # cancel the waiting one: each run also adds the documentation of its own + # version, which no later run would publish. The waiting runs may start in + # another order than their commits, so a run replaces the most recent + # documentation of a module only if no newer version is published already. + concurrency: + group: api-docs-publishing-${{ github.repository }} + queue: max + + # The push goes over SSH with the deploy key, not with `GITHUB_TOKEN`, which + # only reads the dependencies published to GitHub Packages. + permissions: + contents: read + packages: read + + steps: + - uses: actions/checkout@v6 + with: + submodules: 'true' + + - uses: actions/setup-java@v5 + with: + java-version: 17 + distribution: zulu + + # The cache stays on, unlike in `publishing.yml`, which turns it off to keep + # its attestation trustworthy: nothing here is attested. A run on `master` + # reads only the caches written by the workflows that run on `master`. + - uses: gradle/actions/setup-gradle@v6 + + # The same step as in `build-on-ubuntu.yml`. For a release version, the build + # runs Dokka for every published module, in parallel, and the Linux runner + # ships with effectively no swap, so a memory peak would be an instant OOM + # kill. It goes before the deploy key is decrypted, so that the action never + # runs with the key on disk. + - name: Add swap space + uses: pierotofy/set-swap-space@v1.0 + with: + swap-size-gb: 8 + + - name: Decrypt Git SSH credentials + run: ./config/scripts/decrypt.sh "$GIT_CREDENTIALS_KEY" ./.github/keys/deploy_key_rsa.gpg ./deploy_key_rsa + env: + GIT_CREDENTIALS_KEY: ${{ secrets.GIT_CREDENTIALS_KEY }} + + # The SSH agent does not accept a key that others can read. The build runs + # `register-ssh-key.sh` to hand the key to the agent. + - name: Set file system permissions + run: chmod 400 ./deploy_key_rsa && chmod +x ./config/scripts/register-ssh-key.sh + + - name: Publish API docs + run: ./gradlew :publishAllApiDocs --stacktrace + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FORMAL_GIT_HUB_PAGES_AUTHOR: developers@spine.io + # https://docs.github.com/en/actions/reference/environment-variables + REPO_SLUG: ${{ github.repository }} # e.g. SpineEventEngine/core-jvm diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8dc7c913bb..4e1479a824 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -30,7 +30,7 @@ on: jobs: publish: name: Publish to Maven repositories - uses: SpineEventEngine/config/.github/workflows/publishing.yml@ad3dff0890c7716cbba3fe2ce17bf4fe5905a318 + uses: SpineEventEngine/config/.github/workflows/publishing.yml@363fc1da3184d001361fa9c327929eb5e05fa673 permissions: contents: read packages: write diff --git a/.github/workflows/revalidate-versions.yml b/.github/workflows/revalidate-versions.yml index 2d2ecb9c6d..59f81803cc 100644 --- a/.github/workflows/revalidate-versions.yml +++ b/.github/workflows/revalidate-versions.yml @@ -5,7 +5,7 @@ # now stale: its publish would collide. GitHub does not re-run a PR's checks when its base # advances, so this workflow does it actively — for each other open PR whose # `version.gradle.kts` version is `<=` the new base version, it posts a failing -# `Version Guard` commit status on the PR head, blocking the merge until the author +# `Version bump` commit status on the PR head, blocking the merge until the author # re-bumps. The status self-clears: the re-bump push runs `increment-guard.yml`, which # posts a fresh `success` on the new head. # @@ -40,14 +40,14 @@ concurrency: jobs: revalidate: - name: Revalidate open PRs + name: Mark stale version bumps runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: submodules: 'true' - - name: Revalidate open PRs against the new base version + - name: Mark open PRs whose version is not above the new base shell: bash env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/buildSrc/src/main/kotlin/BuildExtensions.kt b/buildSrc/src/main/kotlin/BuildExtensions.kt index a69dd1a044..cedacd2588 100644 --- a/buildSrc/src/main/kotlin/BuildExtensions.kt +++ b/buildSrc/src/main/kotlin/BuildExtensions.kt @@ -27,7 +27,6 @@ import io.spine.dependency.test.Kotest import io.spine.dependency.test.Kover import io.spine.gradle.repo.standardToSpineSdk import org.gradle.api.Project -import org.gradle.api.Task import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.file.DuplicatesStrategy import org.gradle.api.tasks.JavaExec @@ -168,7 +167,8 @@ fun Project.configureTaskDependencies() { * Creates a dependency between the Gradle task of *this* name * onto the task with `taskName`. * - * If either of the tasks does not exist in the enclosing `Project`, + * Neither task is created by this method. A task registered later is matched too. + * If either of the tasks never exists in the enclosing `Project`, * this method does nothing. * * This extension is kept local to the `configureTaskDependencies` extension @@ -176,9 +176,8 @@ fun Project.configureTaskDependencies() { */ fun String.dependOn(taskName: String) { val whoDepends = this - val dependOntoTask: Task? = tasks.findByName(taskName) - dependOntoTask?.let { - tasks.findByName(whoDepends)?.dependsOn(it) + tasks.named { it == whoDepends }.configureEach { + dependsOn(tasks.named { it == taskName }) } } @@ -267,19 +266,20 @@ fun JavaExec.remoteDebug(enabled: Boolean = true) { * * The port number is [5566][BuildSettings.REMOTE_DEBUG_PORT]. * + * The task is configured when Gradle creates it, so calling this function + * does not create the task. + * * @param enabled If `true` the task will be suspended. - * @throws IllegalStateException if the task with the given name is not found, or, - * if the task is not of [JavaExec] type. + * @throws IllegalStateException if the task with the given name is not found. + * @throws org.gradle.api.InvalidUserDataException if the task is not of [JavaExec] type. */ fun Project.setRemoteDebug(taskName: String, enabled: Boolean = true) { - val task = tasks.findByName(taskName) - check(task != null) { + check(taskName in tasks.names) { "Could not find a task named `$taskName` in the project `$name`." } - check(task is JavaExec) { - "The task `$taskName` is not of type `JavaExec`." + tasks.named(taskName, JavaExec::class.java).configure { + remoteDebug(enabled) } - task.remoteDebug(enabled) } /** diff --git a/buildSrc/src/main/kotlin/DokkaExts.kt b/buildSrc/src/main/kotlin/DokkaExts.kt index 5aeba8d5f0..849fea6cb2 100644 --- a/buildSrc/src/main/kotlin/DokkaExts.kt +++ b/buildSrc/src/main/kotlin/DokkaExts.kt @@ -25,6 +25,7 @@ import org.gradle.api.artifacts.dsl.DependencyHandler import org.gradle.api.execution.TaskExecutionGraph import org.gradle.api.publish.maven.tasks.PublishToMavenLocal import org.gradle.api.publish.maven.tasks.PublishToMavenRepository +import org.gradle.api.tasks.TaskCollection import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Jar @@ -183,14 +184,22 @@ fun DokkaExtension.configureForJava(project: Project, sourceLinkRemoteUrl: Strin } /** - * Finds the `dokkaGenerateHtml` Gradle task. + * Finds the `dokkaGeneratePublicationHtml` Gradle task without creating it. + * + * The returned collection is live: it holds the task once Dokka registers it, + * and stays empty in a project without Dokka. */ -fun TaskContainer.dokkaHtmlTask(): Task? = this.findByName("dokkaGeneratePublicationHtml") +fun TaskContainer.dokkaHtmlTask(): TaskCollection = + named { it == "dokkaGeneratePublicationHtml" } /** - * Finds the `dokkaGeneratePublicationJavadoc` Gradle task. + * Finds the `dokkaGeneratePublicationJavadoc` Gradle task without creating it. + * + * The returned collection is live: it holds the task once Dokka registers it, + * and stays empty in a project without Dokka. */ -fun TaskContainer.dokkaJavadocTask(): Task? = this.findByName("dokkaGeneratePublicationJavadoc") +fun TaskContainer.dokkaJavadocTask(): TaskCollection = + named { it == "dokkaGeneratePublicationJavadoc" } /** * Locates or creates the `htmlDocsJar` task in this [Project]. @@ -205,9 +214,7 @@ fun Project.htmlDocsJar(): TaskProvider = tasks.getOrCreate("htmlDocsJar") archiveClassifier.set("html-docs") from(files(dokkaHtmlOutput())) - tasks.dokkaHtmlTask()?.let { dokkaTask -> - this@getOrCreate.dependsOn(dokkaTask) - } + this@getOrCreate.dependsOn(tasks.dokkaHtmlTask()) } /** @@ -238,7 +245,7 @@ fun Task.isInPublishingGraph(): Boolean = * Such a build usually feeds integration tests, which need the published code, * but not its documentation. So the Dokka tasks are skipped when the execution graph * contains a [PublishToMavenLocal] task and no task that ships the documentation - * elsewhere: `publish`, a [PublishToMavenRepository] task, or `updateGitHubPages`. + * elsewhere: `publish`, a [PublishToMavenRepository] task, or `publishApiDocs`. * They still run if a task named on the command line selects a documentation task of * the graph: one that has `dokka` in its name, ignoring case, or a documentation JAR, * `javadocJar` or `htmlDocsJar`. The name may be the full one, e.g., `dokkaGenerate`, @@ -276,7 +283,7 @@ fun Project.skipDokkaWhenPublishingToMavenLocal() { /** * The names of the lifecycle tasks that ship the documentation beyond Maven Local. */ -private val docsShippingTaskNames = setOf("publish", TaskName.updateGitHubPages) +private val docsShippingTaskNames = setOf("publish", TaskName.publishApiDocs) /** * Tells if this graph publishes to Maven Local and does not contain a task that ships diff --git a/buildSrc/src/main/kotlin/dokka-setup.gradle.kts b/buildSrc/src/main/kotlin/dokka-setup.gradle.kts index c66e9f2f4d..43eb56fa75 100644 --- a/buildSrc/src/main/kotlin/dokka-setup.gradle.kts +++ b/buildSrc/src/main/kotlin/dokka-setup.gradle.kts @@ -41,10 +41,7 @@ afterEvaluate { DocumentationSettings.SourceLink.url(project) ) } - val kspKotlin = tasks.findByName("kspKotlin") - kspKotlin?.let { - tasks.withType().configureEach { - dependsOn(kspKotlin) - } + tasks.withType().configureEach { + dependsOn(tasks.named { it == "kspKotlin" }) } } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt index baaf5c7053..e58ab1415e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -25,7 +25,7 @@ package io.spine.dependency.local ) object Base { const val version = "2.0.0-SNAPSHOT.462" - const val versionForBuildScript = "2.0.0-SNAPSHOT.461" + const val versionForBuildScript = "2.0.0-SNAPSHOT.462" const val group = Spine.group private const val prefix = "spine" const val libModule = "$prefix-base" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt index e0a828061a..5f08d0bb3e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/BaseTypes.kt @@ -23,7 +23,7 @@ package io.spine.dependency.local "ConstPropertyName" /* We use a custom convention for artifact properties. */, ) object BaseTypes { - const val version = "2.0.0-SNAPSHOT.225" + const val version = "2.0.0-SNAPSHOT.227" const val group = Spine.group const val artifact = "spine-base-types" const val lib = "$group:$artifact:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt index 1f6ebe1c62..91864be355 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Change.kt @@ -23,7 +23,7 @@ package io.spine.dependency.local "ConstPropertyName" /* We use a custom convention for artifact properties. */, ) object Change { - const val version = "2.0.0-SNAPSHOT.208" + const val version = "2.0.0-SNAPSHOT.209" const val group = Spine.group const val artifact = "spine-change" const val lib = "$group:$artifact:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index 137e830107..b75c0f1ef9 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -60,7 +60,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.069" + private const val fallbackVersion = "2.0.0-SNAPSHOT.081" /** * The distinct version of the Compiler used by other build tools. @@ -69,7 +69,7 @@ object Compiler : Dependency() { * transitive dependencies, this is the version used to build the project itself. */ val dogfoodingVersion: String - private const val fallbackDfVersion = "2.0.0-SNAPSHOT.069" + private const val fallbackDfVersion = "2.0.0-SNAPSHOT.081" /** * The artifact for the Compiler Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt index 35246a7793..94f3d9d682 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt @@ -30,7 +30,7 @@ typealias CoreJava = CoreJvm ) object CoreJvm { const val group = Spine.group - const val version = "2.0.0-SNAPSHOT.571" + const val version = "2.0.0-SNAPSHOT.577" const val coreArtifact = "spine-core" const val clientArtifact = "spine-client" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 1af2694bb1..8fc131eaa8 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -34,12 +34,12 @@ object CoreJvmCompiler { /** * The version used in the build classpath. */ - const val dogfoodingVersion = "2.0.0-SNAPSHOT.097" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.099" /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.097" + const val version = "2.0.0-SNAPSHOT.099" /** * The ID of the Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt index 6026d49f57..4591fac501 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/DokkaTools.kt @@ -25,7 +25,7 @@ package io.spine.dependency.local ) object DokkaTools { const val group = Spine.toolsGroup - const val version = "2.0.0-SNAPSHOT.10" + const val version = "2.0.0-SNAPSHOT.12" /** * The artifact dropped its `spine-` prefix in `2.0.0-SNAPSHOT.9`, to diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt index 96fbbb284c..b84652a194 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt @@ -42,7 +42,22 @@ object Logging { // Transitive dependencies. // Make `public` and use them to force a version in a particular repository, if needed. internal const val julBackend = "$group:spine-logging-jul-backend:$version" + + /** + * The former `middleware` module of Spine Logging. + * + * In `2.0.0-SNAPSHOT.270`, its code moved into the `logging` module, which is + * published as [lib]. The last published version of this artifact is + * `2.0.0-SNAPSHOT.263`, so these coordinates do not resolve at [version]. + * + * @deprecated Use [lib] instead. + */ + @Deprecated( + "The module was merged into `spine-logging` and is no longer published.", + ReplaceWith("lib"), + ) const val middleware = "$group:spine-logging-middleware:$version" + internal const val platformGenerator = "$group:spine-logging-platform-generator:$version" internal const val jvmDefaultPlatform = "$group:spine-logging-jvm-default-platform:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt index 3e8e39938d..d9221c3d7b 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt @@ -28,7 +28,7 @@ import io.spine.dependency.Dependency ) object Time : Dependency() { override val group = Spine.group - override val version = "2.0.0-SNAPSHOT.251" + override val version = "2.0.0-SNAPSHOT.253" private const val infix = "spine-time" fun lib(version: String): String = "$group:$infix:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt index bb675bca2d..905ab2d0d6 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt @@ -33,7 +33,7 @@ package io.spine.dependency.local object ToolBase { const val group = Spine.toolsGroup const val version = "2.0.0-SNAPSHOT.428" - const val dogfoodingVersion = "2.0.0-SNAPSHOT.426" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.428" const val archive = "$group:archive:$version" const val code = "$group:code:$version" @@ -56,6 +56,20 @@ object ToolBase { const val rootGradlePlugins = "$group:root-gradle-plugins:$version" const val gradlePluginApi = "$group:gradle-plugin-api:$version" + + /** + * Stub Gradle plugins for the tests of the `gradle-plugin-api` module. + * + * The `gradle-plugin-api-test-fixtures` module that provides them is internal + * to `tool-base`, which never publishes it to a remote repository. Only + * `publishToMavenLocal` installs it, so these coordinates resolve only from + * a local `~/.m2` copy. + * + * @deprecated There is no replacement. Remove the usage. + */ + @Deprecated( + "The artifact is internal to `tool-base` and is not published remotely. Remove the usage." + ) const val gradlePluginApiTestFixtures = "$group:gradle-plugin-api-test-fixtures:$version" const val jvmTools = "$group:jvm-tools:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt index 155cbbc602..1be9aff47a 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt @@ -27,7 +27,7 @@ object Validation { /** * The version of the Validation library artifacts. */ - const val version = "2.0.0-SNAPSHOT.464" + const val version = "2.0.0-SNAPSHOT.469" const val group = Spine.toolsGroup private const val prefix = "validation" diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/Cli.kt b/buildSrc/src/main/kotlin/io/spine/gradle/Cli.kt index 0e43f3f71f..36ba14ebe3 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/Cli.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/Cli.kt @@ -20,7 +20,6 @@ import java.io.File import java.io.InputStream import java.io.StringWriter import java.lang.ProcessBuilder.Redirect.PIPE -import java.util.* /** * Executes a process from Gradle code. @@ -32,20 +31,34 @@ class Cli(private val workingFolder: File) { /** * Executes the given terminal command and retrieves the command output. * - * [Executes][Runtime.exec] the given `String` array as a CLI command. + * Runs the given command, the program followed by its arguments, in + * the [workingFolder]. * * If the execution is successful, returns the command output. * Throws an [IllegalStateException] otherwise. * * @param command the command to execute. - * @return the command line output. + * @return the standard output as the command wrote it, line breaks included, + * decoded as UTF-8. * @throws IllegalStateException if the execution fails. */ - fun execute(vararg command: String): String { + fun execute(vararg command: String): String = execute(command.asList()) + + /** + * Executes the given terminal command and retrieves the command output. + * + * Works like the `vararg` overload, for a command assembled as a list. + * + * @param command the command to execute, the program followed by its arguments. + * @return the standard output as the command wrote it, line breaks included, + * decoded as UTF-8. + * @throws IllegalStateException if the execution fails. + */ + fun execute(command: List): String { val outWriter = StringWriter() val errWriter = StringWriter() - val process = ProcessBuilder(*command).apply { + val process = ProcessBuilder(command).apply { directory(workingFolder) redirectOutput(PIPE) redirectError(PIPE) @@ -66,22 +79,22 @@ class Cli(private val workingFolder: File) { val commandLine = command.joinToString(" ") val nl = System.lineSeparator() val errorMsg = "Command `$commandLine` finished with exit code $exitCode:" + - "$nl$errWriter" + - "$nl$outWriter." + "$nl${errWriter.toString().trimEnd()}" + + "$nl${outWriter.toString().trimEnd()}." throw IllegalStateException(errorMsg) } } } /** - * Starts a background thread that reads all lines from this [InputStream] and - * appends them to [dest], returning the thread so the caller can [join][Thread.join] - * it once the process has exited, ensuring the buffer holds the complete output. + * Starts a background thread that reads all of this [InputStream] and appends it + * to [dest], returning the thread so the caller can [join][Thread.join] it once + * the process has exited, ensuring the buffer holds the complete output. + * + * The text is appended as the process wrote it, line breaks included, so that + * a multi-line output can be split into lines. */ private fun InputStream.pourTo(dest: StringWriter): Thread = Thread { - val sc = Scanner(this) - while (sc.hasNextLine()) { - dest.append(sc.nextLine()) - } + bufferedReader().use { dest.append(it.readText()) } }.also { it.start() } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt index 41cac88758..5c16bd5661 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/ProjectExtensions.kt @@ -59,7 +59,11 @@ fun Project.applyPlugin(cls: Class>) { * * The task must be present. Also, a caller is responsible for using the proper value of * the generic parameter `T`. + * + * Gradle creates the task if it is only registered so far, even in a build that never + * runs it. Prefer `tasks.named(name)`, which finds the task without creating it. */ +@Deprecated(message = "Please use `tasks.named(name)`, which does not create the task.") @Suppress("UNCHECKED_CAST") /* See the method docs. */ fun Project.getTask(name: String): T { val task = this.tasks.findByName(name) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/TaskName.kt b/buildSrc/src/main/kotlin/io/spine/gradle/TaskName.kt index 0a595b3b40..763b9832b2 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/TaskName.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/TaskName.kt @@ -17,6 +17,7 @@ package io.spine.gradle import kotlin.reflect.KClass import org.gradle.api.Task import org.gradle.api.tasks.TaskContainer +import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.register @@ -45,3 +46,22 @@ internal fun TaskContainer.named(name: TaskName) = named(name.valu */ internal fun TaskContainer.register(name: TaskName, init: T.() -> Unit) = register(name.value, name.clazz, init) + +/** + * Returns the task named [name] in this container, registering it with [init] + * if it is not there yet. + * + * Unlike [register][TaskContainer.register], this does not fail when the task is + * already registered, so it suits code that may reach the same task more than once. + * [init] applies only when this call registers the task; for an existing task it is + * ignored, so a setup needed in both cases goes to [TaskProvider.configure]. + */ +internal fun TaskContainer.getOrRegister( + name: String, + init: Task.() -> Unit = {} +): TaskProvider = + if (name in names) { + named(name) + } else { + register(name, init) + } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/checkstyle/CheckStyleConfig.kt b/buildSrc/src/main/kotlin/io/spine/gradle/checkstyle/CheckStyleConfig.kt index b8232683fa..79351fbf16 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/checkstyle/CheckStyleConfig.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/checkstyle/CheckStyleConfig.kt @@ -64,7 +64,7 @@ object CheckStyleConfig { "checkstyleTest", "checkstyleTestFixtures" ).forEach { - task -> tasks.findByName(task)?.enabled = false + task -> tasks.named { it == task }.configureEach { enabled = false } } } } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt b/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt index 1b7e09abf9..6630f985f2 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/git/Repository.kt @@ -61,14 +61,33 @@ class Repository private constructor( repoExecute("git", "clone", sshUrl, ".") } + /** + * Clones the tip of the [branch], or of the default branch if it is `null`, + * into the [temporary folder][location]. + * + * The blobs are fetched only when the working tree needs them, and the working + * tree holds only the top-level files until [checkOutOnly] replaces them with + * the selected paths. + */ + private fun cloneSparsely(branch: String?) { + val options = listOf("--depth", "1", "--filter=blob:none", "--sparse", "--single-branch") + val branchOption = branch?.let { listOf("--branch", it) } ?: emptyList() + repoExecute(listOf("git", "clone") + options + branchOption + listOf("--", sshUrl, ".")) + } + /** * Executes a command in the [location]. */ - private fun repoExecute(vararg command: String): String { - val cmd = command.toList().joinToString(" ") + private fun repoExecute(vararg command: String): String = repoExecute(command.asList()) + + /** + * Executes a command, assembled as a list, in the [location]. + */ + private fun repoExecute(command: List): String { + val cmd = command.joinToString(" ") val msg = "[Repo (${project.path})] Executing command: `$cmd`." System.err.println(msg) - return Cli(location.toFile()).execute(*command) + return Cli(location.toFile()).execute(command) } /** @@ -125,12 +144,59 @@ class Repository private constructor( * match a namespaced branch such as `feature/$name`. Relies on `git ls-remote` * returning an empty output with a zero exit code when the branch is absent, * so the check does not raise an exception. + * + * @param name the name of the branch. + * @param remote the name of the remote or its URL; `origin` by default. */ - private fun remoteHasBranch(name: String): Boolean { - val output = repoExecute("git", "ls-remote", "--heads", "origin", "refs/heads/$name") + private fun remoteHasBranch(name: String, remote: String = "origin"): Boolean { + val output = repoExecute("git", "ls-remote", "--heads", remote, "refs/heads/$name") return output.isNotBlank() } + /** + * Checks out only the paths of the current branch that match the given [patterns], + * leaving the rest of the branch out of the working tree. + * + * The call replaces the paths checked out before, including the top-level files + * of a [sparse clone][Factory.cloneSparsely], so it has to be given every path + * to keep at once. + * + * The patterns follow the `.gitignore` syntax, so a folder can be checked out + * without some of its subfolders. The paths left out stay in the branch: committing + * [all changes][commitAllChanges] does not delete them. + * + * Leaving out some subfolders of a folder takes the non-cone mode of + * `git sparse-checkout`, which Git documents as deprecated, though Git 2.54 still + * supports it without a warning. The mode needs Git 2.35 or newer. + */ + fun checkOutOnly(patterns: List) { + repoExecute(listOf("git", "sparse-checkout", "set", "--no-cone") + patterns) + } + + /** + * Obtains the names of the folders in the given [folder] of the current commit, + * whether they are checked out or not. + * + * Reads the tree of the current commit, so the changes in the working tree that + * are not committed yet are not reflected. The files in the [folder] are skipped. + * + * @param folder the path of the folder relative to the repository root. + * @return the names of the folders in [folder], or an empty list if there is + * no such folder. + */ + fun listFolders(folder: String): List { + require(folder.isNotBlank()) { "The folder to list cannot be blank." } + // Each entry is ` \t`, the entries are separated + // by `NUL`, and the paths are not quoted. + return repoExecute("git", "ls-tree", "-z", "HEAD", "${folder.trimEnd('/')}/") + .split('\u0000') + .filter { it.isNotBlank() } + .mapNotNull { entry -> + val (info, path) = entry.split('\t', limit = 2) + path.substringAfterLast('/').takeIf { info.split(' ')[1] == "tree" } + } + } + /** * Creates the [branch] as an orphan branch seeded with [initialFiles] and * pushes it to the remote. @@ -173,7 +239,6 @@ class Repository private constructor( // If the branch now exists on the remote, another module won the // creation race and we adopt its branch; otherwise the failure is // genuine and is rethrown. - repoExecute("git", "fetch", "origin") if (!remoteHasBranch(branch)) { throw e } @@ -184,8 +249,14 @@ class Repository private constructor( /** * Discards the local orphan branch in favour of the same-named branch that * already exists on the remote, keeping the local branch in sync with it. + * + * The branch is added to the branches fetched from the remote first: a single-branch + * clone, which a shallow one is too, fetches no other branch, and Git does not + * accept a branch it does not fetch as the upstream of a local one. */ private fun adoptRemoteBranch(branch: String) { + repoExecute("git", "remote", "set-branches", "--add", "origin", branch) + repoExecute("git", "fetch", "origin", "+refs/heads/$branch:refs/remotes/origin/$branch") repoExecute("git", "reset", "--hard", "origin/$branch") repoExecute("git", "branch", "--set-upstream-to=origin/$branch", branch) } @@ -274,6 +345,53 @@ class Repository private constructor( return repo } + + /** + * Clones the tip of the [branch] of the repository with the provided SSH URL + * in a temporary folder, with only its top-level files checked out. + * + * Suits a branch with a large tip of which a change touches only a small part, + * such as the branch with the documentation of every published version. + * Further blobs are fetched only for the paths that [checkOutOnly] selects. + * The commits are made and [pushed][push] as in a full clone. + * + * A [branch] that does not exist yet is created and seeded with [initialFiles], + * which are top-level files. + * + * Configures the username and the email of the Git user. + * See [configureUser] documentation for more information. + * + * @throws IllegalArgumentException if SSH URL is a blank string. + */ + fun cloneSparsely( + project: Project, + sshUrl: String, + user: UserInfo, + branch: String, + initialFiles: Map = emptyMap(), + ): Repository { + require(sshUrl.isNotBlank()) { "SSH URL cannot be an empty string." } + + val repo = Repository(project, sshUrl = sshUrl, user = user, currentBranch = branch) + var cloned = false + try { + // Ask the remote first: an existing branch is cloned alone, while + // a missing one needs the default branch to start from. + val branchExists = repo.remoteHasBranch(branch, remote = sshUrl) + repo.cloneSparsely(branch.takeIf { branchExists }) + repo.configureUser(user) + if (!branchExists) { + repo.createOrphanBranch(branch, initialFiles) + } + cloned = true + return repo + } finally { + // The caller cannot close a repository it never gets. + if (!cloned) { + repo.close() + } + } + } } } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/AuthorEmail.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/AuthorEmail.kt index 39d16ac8fd..cec12afdc9 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/AuthorEmail.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/AuthorEmail.kt @@ -15,7 +15,8 @@ package io.spine.gradle.github.pages /** - * An author of updates to GitHub pages. + * The email of the author of the commits that publish the API documentation + * to GitHub Pages. */ class AuthorEmail(val value: String) { diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/DocsPublication.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/DocsPublication.kt new file mode 100644 index 0000000000..11f37da3b0 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/DocsPublication.kt @@ -0,0 +1,254 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.gradle.github.pages + +import io.spine.gradle.VersionComparator +import io.spine.gradle.git.Repository +import java.io.File +import java.nio.file.Path +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.FileCollection +import org.gradle.api.logging.Logger + +/** + * Publishes the API documentation of the given [project] to GitHub Pages. + * + * The documentation in each format is copied into a clone of the `gh-pages` branch + * and committed there, and the commits are pushed. + * + * The clone has only the most recent documentation of the [project] and the folder of + * its version checked out, without the folders of the versions published earlier. + * The branch holds the documentation of every version of every module, which is too + * much to check out for a change to a single module. + */ +internal fun Task.publishToGitHubPages(project: Project) { + val plugin = project.plugins.getPlugin(PublishApiDocs::class.java) + + SshKey(plugin.rootFolder, logger).register() + + val repository = Repository.forPublishingDocumentation(project) + + val javadoc = JavadocPublication(project, plugin.javadocOutputFolder, repository, logger) + val html = HtmlPublication(project, plugin.htmlOutputFolder, repository, logger) + + repository.use { + repository.checkOutOnly(javadoc.checkoutPatterns() + html.checkoutPatterns()) + javadoc.publish() + html.publish() + repository.push() + } +} + +/** + * Publishes the documentation of a [project] in one format to the clone of + * the [repository] serving GitHub Pages. + * + * The documentation goes to the folder of its version, and also replaces the most + * recent documentation of the project, unless a newer version is already published. + */ +private abstract class DocsPublication( + private val project: Project, + private val docsSourceFolder: Path, + private val repository: Repository, + private val logger: Logger +) { + + /** + * The folder under the repository's root(`/`) for storing documentation. + * + * The value should not contain any leading or trailing file separators. + * + * The absolute path to the project's documentation is made by appending its + * name to the end, making `/docsDestinationFolder/project.name`. + */ + protected abstract val docsDestinationFolder: String + + /** + * The name of the format of the documentation to publish. + * + * This name will appear in logs as part of a message. + */ + protected abstract val formatName: String + + /** + * The path of the folder with the documentation of the [project] in this format, + * relative to the repository root. + */ + private val folder: String + get() = "$docsDestinationFolder/${project.name}" + + private val mostRecentFolder by lazy { + File("${repository.location}/$folder") + } + + /** + * The folder holding the documentation of each published version in a subfolder + * named after the version. + */ + private val versionsFolder by lazy { + File(mostRecentFolder, VERSIONS_FOLDER) + } + + private fun log(message: () -> String) { + if (logger.isDebugEnabled) { + logger.debug(message()) + } + } + + /** + * Obtains the patterns of the paths this publication writes, for + * [checking out][Repository.checkOutOnly] just those paths. + */ + fun checkoutPatterns(): List = + docsCheckoutPatterns(folder, project.version.toString()) + + /** + * Copies the documentation into the repository and commits it. + */ + fun publish() { + val module = project.name + log { "Publishing the `$formatName` documentation of the module `$module`." } + + val documentation = replaceMostRecentDocs() + copyIntoVersionDir(documentation) + + val version = project.version + val commitMessage = + "Publish the `$formatName` documentation of the module" + + " `$module` for the version `$version`." + repository.commitAllChanges(commitMessage) + + log { "Published the `$formatName` documentation of the module `$module`." } + } + + /** + * Replaces the most recent documentation with the one of this version, unless + * the documentation of a newer version is already published. + * + * The runs of `publish-api-docs.yml` are serialized, but not necessarily in the + * order of their commits, and a release of an older line may come after a newer + * one. Either way, the most recent documentation stays that of the newest version. + */ + private fun replaceMostRecentDocs(): ConfigurableFileCollection { + val generatedDocs = project.files(docsSourceFolder) + + val version = project.version.toString() + val newer = publishedVersions().newestAbove(version) + if (newer != null) { + logger.lifecycle( + "The most recent `$formatName` documentation of `${project.name}` stays" + + " that of `$newer`, which is newer than `$version`." + ) + return generatedDocs + } + + log { "Replacing the most recent `$formatName` documentation in `$mostRecentFolder`." } + copyDocs(generatedDocs, mostRecentFolder) + + return generatedDocs + } + + /** + * Obtains the versions whose documentation is published, as named by the folders + * under `v/`. + * + * The names are read from the tree of the current commit, as the folders of + * the other versions are not checked out. + */ + private fun publishedVersions(): List = + repository.listFolders("$folder/$VERSIONS_FOLDER") + + private fun copyDocs(source: FileCollection, destination: File) { + destination.mkdirs() + project.copy { + from(source) + into(destination) + } + } + + private fun copyIntoVersionDir(generatedDocs: ConfigurableFileCollection) { + val versionedDocDir = File(versionsFolder, "${project.version}") + + log { "Storing the new version of `$formatName` documentation in `${versionedDocDir}`." } + copyDocs(generatedDocs, versionedDocDir) + } +} + +private class JavadocPublication( + project: Project, + docsSourceFolder: Path, + repository: Repository, + logger: Logger +) : DocsPublication(project, docsSourceFolder, repository, logger) { + + override val docsDestinationFolder: String + get() = "javadoc" + override val formatName: String + get() = "javadoc" +} + +private class HtmlPublication( + project: Project, + docsSourceFolder: Path, + repository: Repository, + logger: Logger +) : DocsPublication(project, docsSourceFolder, repository, logger) { + + override val docsDestinationFolder: String + get() = "reference" + override val formatName: String + get() = "html" +} + +/** + * Returns the newest of these versions if it is newer than the given [version], + * or `null` otherwise. + * + * The versions are compared by [VersionComparator], so that `2.10.0` is newer than + * `2.9.0`, and a release is newer than the snapshots leading to it. + */ +internal fun Iterable.newestAbove(version: String): String? = + maxWithOrNull(VersionComparator)?.takeIf { VersionComparator.compare(it, version) > 0 } + +/** + * The name of the folder that holds the documentation of each published version + * in a subfolder named after the version. + */ +private const val VERSIONS_FOLDER = "v" + +/** + * Returns the patterns, in the `.gitignore` syntax, of the paths that a publication + * of the documentation in the given [folder] writes: the most recent documentation, + * and the folder of the given [version] under `v/`, but not the folders of the other + * versions. + * + * The folders under `v/` are excluded one by one, and the folder of the [version] + * is included again after them, as the last matching pattern wins. This is how + * `git sparse-checkout` lays out its patterns in cone mode. + * + * For example, for the `javadoc/core` folder and the version `1.2.0`, the patterns + * select everything in `javadoc/core`, exclude each folder in `javadoc/core/v`, and + * select `javadoc/core/v/1.2.0` again. + * + * @param folder the path of the documentation folder, relative to the repository root. + * @param version the version whose folder is included. + */ +internal fun docsCheckoutPatterns(folder: String, version: String): List = listOf( + "/$folder/*", + "!/$folder/$VERSIONS_FOLDER/*/", + "/$folder/$VERSIONS_FOLDER/$version/", +) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishAllApiDocs.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishAllApiDocs.kt new file mode 100644 index 0000000000..e610c5861e --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishAllApiDocs.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.gradle.github.pages + +import io.spine.gradle.SpineTaskGroup +import io.spine.gradle.getOrRegister +import io.spine.gradle.github.pages.TaskName.publishAllApiDocs +import io.spine.gradle.github.pages.TaskName.publishApiDocs +import org.gradle.api.Project + +/** + * Registers the [TaskName.publishAllApiDocs] task in the root project, which publishes + * the API documentation of all the published projects of the build. + * + * Usage: + * ``` + * PublishAllApiDocs.registerIn(project.rootProject, projectsToPublish) + * ``` + * + * `spinePublishing { }` makes this call, as it knows which projects are published. + * The task is not a part of the publication to Maven repositories: the + * `publish-api-docs.yml` workflow runs it apart from `publish`. + * + * The task is a lifecycle one: it has no action of its own, and publishes + * the documentation through the [TaskName.publishApiDocs] tasks it depends on, + * which the [PublishApiDocs] plugin registers in each documented project. + */ +internal object PublishAllApiDocs { + + /** + * Registers the [TaskName.publishAllApiDocs] task in the [root] project. + * The task publishes the API documentation of the [published] projects. + * + * The task depends on the [TaskName.publishApiDocs] task of each of + * the [published] projects that has one, that is, applies the [PublishApiDocs] + * plugin. This includes [root] when it is published itself, as in a single-project + * build. A project that applies the plugin, but is not published, such as a module + * of integration tests, is left out. The task of a project with a snapshot version + * publishes nothing. + * + * The task is registered even when none of the projects has the documentation + * to publish, and then does nothing. This lets the `publish-api-docs.yml` + * workflow run it in any repository that publishes: Gradle fails on a task + * that is missing from the build. + * + * The plugin registers the task of a project once that project is evaluated, + * so the tasks to depend on are looked up only when Gradle resolves + * the dependencies of this task. Repeated calls add their projects to the same + * task, as `spinePublishing { }` may run more than once in a build. + */ + fun registerIn(root: Project, published: Set) { + val task = root.tasks.getOrRegister(publishAllApiDocs) { + group = SpineTaskGroup.name + description = "Publishes the API documentation of all the published modules" + } + task.configure { + dependsOn(root.provider { + published + .filter { publishApiDocs in it.tasks.names } + .map { it.tasks.named(publishApiDocs) } + }) + } + } +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPages.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishApiDocs.kt similarity index 65% rename from buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPages.kt rename to buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishApiDocs.kt index e4960aaf71..f4ca18bc31 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPages.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishApiDocs.kt @@ -15,12 +15,12 @@ package io.spine.gradle.github.pages import dokkaHtmlTask -import dokkaJavadocTask import io.spine.gradle.SpineTaskGroup import io.spine.gradle.fs.LazyTempPath import io.spine.gradle.github.pages.TaskName.copyHtmlDocs import io.spine.gradle.github.pages.TaskName.copyJavadocDocs -import io.spine.gradle.github.pages.TaskName.updateGitHubPages +import io.spine.gradle.github.pages.TaskName.publishApiDocs +import io.spine.gradle.isSnapshot import java.io.File import org.gradle.api.Plugin import org.gradle.api.Project @@ -30,12 +30,18 @@ import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskProvider /** - * Registers the `updateGitHubPages` task that performs the update of - * the GitHub Pages with the documentation generated in Javadoc and HTML format - * for a particular Gradle project. + * Registers the `publishApiDocs` task that publishes the API documentation + * of a particular Gradle project, generated in Javadoc and HTML format. * * The generated documentation is appended to the `spine.io` site - * via GitHub pages by pushing commits to the `gh-pages` branch. + * via GitHub Pages by pushing commits to the `gh-pages` branch. + * The documentation of a snapshot version is not published to the site. Its Javadoc and + * HTML archives are still built by Dokka and published to Maven repositories by `publish`. + * + * The task is not a part of the Maven publication. It is run by the `publish-api-docs.yml` + * workflow, apart from `publish.yml`, through the `publishAllApiDocs` task of the root + * project, which [publishes the documentation of the published modules that apply + * this plugin][PublishAllApiDocs]. * * In order to work, the script needs a `deploy_key_rsa` private RSA key file in the * repository root. It is recommended to encrypt it in the repository and then decrypt @@ -47,18 +53,18 @@ import org.gradle.api.tasks.TaskProvider * the SSH private (encrypted `deploy_key_rsa`) and the public * ("GitHub Pages publisher" on GitHub) keys. * - * Another requirement is an environment variable `REPO_SLUG`, which is set by the CI - * environment, such as `Publish` GitHub Actions workflow. It points to the repository - * for which the update is executed. E.g.: + * Another requirement is an environment variable `REPO_SLUG`, which a CI workflow sets, + * such as the `Publish API docs` GitHub Actions workflow. It points to + * the repository for which the documentation is published. E.g.: * * ``` * REPO_SLUG: SpineEventEngine/base * ``` * - * @see UpdateGitHubPagesExtension for the extension that is used to configure + * @see PublishApiDocsExtension for the extension that is used to configure * this plugin */ -class UpdateGitHubPages : Plugin { +class PublishApiDocs : Plugin { /** * Root folder of the repository, to which this `Project` belongs. @@ -74,13 +80,13 @@ class UpdateGitHubPages : Plugin { /** * Path to the temp folder used to gather the Javadoc format output (generated by Dokka) - * before submitting it to the GitHub Pages update. + * before publishing it. */ internal val javadocOutputFolder = LazyTempPath("javadoc") /** * Path to the temp folder used to gather the HTML documentation - * generated by Dokka before submitting it to the GitHub Pages update. + * generated by Dokka before publishing it. */ internal val htmlOutputFolder = LazyTempPath("html") @@ -94,41 +100,45 @@ class UpdateGitHubPages : Plugin { * when the project version changes to non-snapshot. */ override fun apply(project: Project) { - val extension = UpdateGitHubPagesExtension.createIn(project) + val extension = PublishApiDocsExtension.createIn(project) project.afterEvaluate { - registerTasks(extension) + if (version.toString().isSnapshot()) { + registerNoOpTask() + } else { + registerTasks(extension) + } } } /** - * Registers the `updateGitHubPages` task that performs no actual update, but prints - * the message telling the update is skipped, since the project is in - * its `SNAPSHOT` version. + * Registers the [TaskName.publishApiDocs] task that publishes nothing, but tells + * that the documentation is not published, since the project is in its `SNAPSHOT` + * version. */ - @Suppress("unused") private fun Project.registerNoOpTask() { - tasks.register(updateGitHubPages) { + val module = name + val snapshotVersion = version.toString() + tasks.register(publishApiDocs) { group = SpineTaskGroup.name - description = "Skips the GitHub Pages update for snapshot project versions" + description = "Skips publishing the API documentation of snapshot versions" doLast { - val project = this@registerNoOpTask - println( - "GitHub Pages update will be skipped since this project is a snapshot: " + - "`${project.name}-${project.version}`." + logger.lifecycle( + "The API documentation of `$module` is not published, since" + + " `$snapshotVersion` is a snapshot version." ) } } } - private fun Project.registerTasks(extension: UpdateGitHubPagesExtension) { + private fun Project.registerTasks(extension: PublishApiDocsExtension) { rootFolder = extension.rootFolder() includedInputs = extension.includedInputs() tasks.registerCopyJavadoc() tasks.registerCopyDokka() - val updatePagesTask = tasks.registerUpdateTask() - updatePagesTask.configure { + val publishTask = tasks.registerPublishTask() + publishTask.configure { dependsOn(copyJavadocDocs) dependsOn(copyHtmlDocs) } @@ -147,7 +157,8 @@ class UpdateGitHubPages : Plugin { private fun TaskContainer.composeJavadocInputs(): List { val inputs = mutableListOf() - inputs.add(dokkaJavadocTask()!!) + // Unlike the HTML docs, the Javadoc is required, so a missing task fails the build. + inputs.add(named("dokkaGeneratePublicationJavadoc")) inputs.addAll(includedInputs) return inputs } @@ -165,22 +176,19 @@ class UpdateGitHubPages : Plugin { private fun TaskContainer.composeDokkaInputs(): List { val inputs = mutableListOf() - - dokkaHtmlTask()?.let { - inputs.add(it) - } + inputs.add(dokkaHtmlTask()) inputs.addAll(includedInputs) return inputs } - private fun TaskContainer.registerUpdateTask(): TaskProvider { - return register(updateGitHubPages) { + private fun TaskContainer.registerPublishTask(): TaskProvider { + return register(publishApiDocs) { group = SpineTaskGroup.name - description = "Publishes the generated documentation to the `gh-pages` branch" + description = "Publishes the API documentation to the `gh-pages` branch" doLast { try { - updateGhPages(project) + publishToGitHubPages(project) } finally { cleanup() } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPagesExtension.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishApiDocsExtension.kt similarity index 70% rename from buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPagesExtension.kt rename to buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishApiDocsExtension.kt index 5a7b1a88f0..fbf0d9bc96 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/UpdateGitHubPagesExtension.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/PublishApiDocsExtension.kt @@ -23,44 +23,44 @@ import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.property /** - * Configures the `updateGitHubPages` extension. + * Configures the `publishApiDocs` extension. */ @Suppress("unused") -fun Project.updateGitHubPages( - action: UpdateGitHubPagesExtension.() -> Unit +fun Project.publishApiDocs( + action: PublishApiDocsExtension.() -> Unit ) { - apply() + apply() - val extension = extensions.getByType(UpdateGitHubPagesExtension::class) + val extension = extensions.getByType(PublishApiDocsExtension::class) extension.action() } /** - * The extension for configuring the [UpdateGitHubPages] plugin. + * The extension for configuring the [PublishApiDocs] plugin. * - * @property rootFolder The root folder of the repository to which the updated `Project` belongs. + * @property rootFolder The root folder of the repository to which the documented `Project` belongs. * @property includeInputs The external inputs, which output should be included - * into the GitHub Pages update. The values are interpreted according to + * into the published documentation. The values are interpreted according to * [Copy.from][org.gradle.api.tasks.Copy.from] specification. * This property is optional. */ -class UpdateGitHubPagesExtension private constructor( - var rootFolder: Property, - var includeInputs: SetProperty +class PublishApiDocsExtension private constructor( + val rootFolder: Property, + val includeInputs: SetProperty ) { internal companion object { /** * The name of the extension. */ - const val name = "updateGitHubPages" + const val name = "publishApiDocs" /** * Creates a new extension and adds it to the passed project. */ - fun createIn(project: Project): UpdateGitHubPagesExtension { + fun createIn(project: Project): PublishApiDocsExtension { val factory = project.objects - val result = UpdateGitHubPagesExtension( + val result = PublishApiDocsExtension( rootFolder = factory.property(File::class), includeInputs = factory.setProperty(Any::class.java) ) @@ -76,8 +76,8 @@ class UpdateGitHubPagesExtension private constructor( fun rootFolder(): File = rootFolder.get() /** - * Returns the external inputs, which results should be included into the - * GitHub Pages update. + * Returns the external inputs, whose results should be included into the + * published documentation. */ fun includedInputs(): Set = includeInputs.get() } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/RepositoryExtensions.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/RepositoryExtensions.kt index 0be661d2e6..8a704cb949 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/RepositoryExtensions.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/RepositoryExtensions.kt @@ -21,17 +21,19 @@ import io.spine.gradle.repo.RepoSlug import org.gradle.api.Project /** - * Clones the current project repository with the branch dedicated to publishing - * documentation to GitHub Pages checked out. + * Clones the branch of the current project repository dedicated to publishing + * documentation to GitHub Pages. * * The repository's GitHub SSH URL is derived from the `REPO_SLUG` environment * variable. The [branch][Branch.documentation] dedicated to publishing documentation - * is automatically checked out in this repository, and created if it does not exist - * yet. A freshly created branch is seeded with a `CNAME` file so that GitHub Pages - * serves the documentation under the `spine.io` custom domain. Also, the username - * and the email of the git user are automatically configured. + * is cloned [sparsely][Repository.Factory.cloneSparsely]: its tip holds the documentation + * of every published version of every module, while a publication touches the folders + * of one module only; the caller [checks them out][Repository.checkOutOnly]. The branch + * is created if it does not exist yet. A freshly created branch is seeded with a `CNAME` + * file so that GitHub Pages serves the documentation under the `spine.io` custom domain. + * Also, the username and the email of the Git user are automatically configured. * - * The username is set to `"UpdateGitHubPages Plugin"`, and the email is derived from + * The username is set to `"PublishApiDocs Plugin"`, and the email is derived from * the `FORMAL_GIT_HUB_PAGES_AUTHOR` environment variable. * * @throws org.gradle.api.GradleException if any of the environment variables described above @@ -40,7 +42,7 @@ import org.gradle.api.Project internal fun Repository.Factory.forPublishingDocumentation(project: Project): Repository { val host = RepoSlug.fromVar().gitHost() - val username = "UpdateGitHubPages Plugin" + val username = "PublishApiDocs Plugin" val userEmail = AuthorEmail.fromVar().toString() val user = UserInfo(username, userEmail) @@ -51,5 +53,11 @@ internal fun Repository.Factory.forPublishingDocumentation(project: Project): Re // custom domain. val initialFiles = mapOf("CNAME" to "spine.io\n") - return clone(project, host, user, branch, initialFiles) + return cloneSparsely( + project, + sshUrl = host, + user = user, + branch = branch, + initialFiles = initialFiles + ) } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/TaskName.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/TaskName.kt index cc453f0bf8..2d7d20de25 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/TaskName.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/TaskName.kt @@ -17,19 +17,25 @@ package io.spine.gradle.github.pages object TaskName { /** - * The name of the task that updates the GitHub Pages. + * The name of the task that publishes the API documentation of a project. */ - const val updateGitHubPages = "updateGitHubPages" + const val publishApiDocs = "publishApiDocs" /** - * The name of the helper task to gather the generated Javadoc format - * documentation generated by Dokka before updating GitHub Pages. + * The name of the task of the root project that publishes the API documentation + * of all the published projects of the build. + */ + const val publishAllApiDocs = "publishAllApiDocs" + + /** + * The name of the helper task to gather the Javadoc format documentation + * generated by Dokka before publishing it to GitHub Pages. */ const val copyJavadocDocs = "copyJavadocDocs" /** * The name of the helper task to gather HTML documentation - * generated by Dokka before updating GitHub Pages. + * generated by Dokka before publishing it to GitHub Pages. */ const val copyHtmlDocs = "copyHtmlDocs" } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/Update.kt b/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/Update.kt deleted file mode 100644 index 29896d159f..0000000000 --- a/buildSrc/src/main/kotlin/io/spine/gradle/github/pages/Update.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2026 CodeMatters, Lda. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under - * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - */ - -package io.spine.gradle.github.pages - -import io.spine.gradle.git.Repository -import java.io.File -import java.nio.file.Path -import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.FileCollection -import org.gradle.api.logging.Logger - -/** - * Performs the update of GitHub pages. - */ -fun Task.updateGhPages(project: Project) { - val plugin = project.plugins.getPlugin(UpdateGitHubPages::class.java) - - SshKey(plugin.rootFolder, logger).register() - - val repository = Repository.forPublishingDocumentation(project) - - val updateJavadocFormat = - UpdateJavadocFormat(project, plugin.javadocOutputFolder, repository, logger) - - val updateHtmlFormat = - UpdateHtmlFormat(project, plugin.htmlOutputFolder, repository, logger) - - repository.use { - updateJavadocFormat.run() - updateHtmlFormat.run() - repository.push() - } -} - -private abstract class UpdateDocumentation( - private val project: Project, - private val docsSourceFolder: Path, - private val repository: Repository, - private val logger: Logger -) { - - /** - * The folder under the repository's root(`/`) for storing documentation. - * - * The value should not contain any leading or trailing file separators. - * - * The absolute path to the project's documentation is made by appending its - * name to the end, making `/docsDestinationFolder/project.name`. - */ - protected abstract val docsDestinationFolder: String - - /** - * The name of the format of the documentation to update. - * - * This name will appear in logs as part of a message. - */ - protected abstract val formatName: String - - private val mostRecentFolder by lazy { - File("${repository.location}/${docsDestinationFolder}/${project.name}") - } - - private fun log(message: () -> String) { - if (logger.isDebugEnabled) { - logger.debug(message()) - } - } - - fun run() { - val module = project.name - log { "Update of the `$formatName` documentation for the module `$module` started." } - - val documentation = replaceMostRecentDocs() - copyIntoVersionDir(documentation) - - val version = project.version - val updateMessage = - "Update `$formatName` documentation for the module" + - " `$module` with the version `$version`." - repository.commitAllChanges(updateMessage) - - log { "Update of the `$formatName` documentation for `$module` successfully finished." } - } - - private fun replaceMostRecentDocs(): ConfigurableFileCollection { - val generatedDocs = project.files(docsSourceFolder) - - log { "Replacing the most recent `$formatName` documentation in `$mostRecentFolder`." } - copyDocs(generatedDocs, mostRecentFolder) - - return generatedDocs - } - - private fun copyDocs(source: FileCollection, destination: File) { - destination.mkdir() - project.copy { - from(source) - into(destination) - } - } - - private fun copyIntoVersionDir(generatedDocs: ConfigurableFileCollection) { - val versionedDocDir = File("$mostRecentFolder/v/${project.version}") - - log { "Storing the new version of `$formatName` documentation in `${versionedDocDir}`." } - copyDocs(generatedDocs, versionedDocDir) - } -} - -private class UpdateJavadocFormat( - project: Project, - docsSourceFolder: Path, - repository: Repository, - logger: Logger -) : UpdateDocumentation(project, docsSourceFolder, repository, logger) { - - override val docsDestinationFolder: String - get() = "javadoc" - override val formatName: String - get() = "javadoc" -} - -private class UpdateHtmlFormat( - project: Project, - docsSourceFolder: Path, - repository: Repository, - logger: Logger -) : UpdateDocumentation(project, docsSourceFolder, repository, logger) { - - override val docsDestinationFolder: String - get() = "reference" - override val formatName: String - get() = "html" -} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt index 825d3254fc..d346328537 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/ExcludeInternalDoclet.kt @@ -89,7 +89,7 @@ private fun Project.appendCustomJavadocTask(excludeInternalDoclet: Configuration !it.absolutePath.contains("generated") }.asFileTree - classpath = javadocTask.classpath + classpath = javadocTask.get().classpath options { encoding = JavadocConfig.encoding.name diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt index cb6998de2f..35ff1fbc3a 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/javadoc/JavadocConfig.kt @@ -19,19 +19,25 @@ import java.io.File import org.gradle.api.JavaVersion import org.gradle.api.Project import org.gradle.api.tasks.TaskContainer +import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.javadoc.Javadoc import org.gradle.external.javadoc.StandardJavadocDocletOptions import productionModules /** - * Finds a [Javadoc] Gradle task by the passed name. + * Finds a [Javadoc] Gradle task by the passed name without creating it. + * + * The task must be registered. */ -fun TaskContainer.javadocTask(named: String) = this.getByName(named) as Javadoc +fun TaskContainer.javadocTask(named: String): TaskProvider = + this.named(named, Javadoc::class.java) /** - * Finds a default [Javadoc] Gradle task. + * Finds a default [Javadoc] Gradle task without creating it. + * + * The task must be registered. */ -fun TaskContainer.javadocTask() = this.getByName("javadoc") as Javadoc +fun TaskContainer.javadocTask(): TaskProvider = javadocTask("javadoc") /** * Javadoc processing settings. @@ -57,15 +63,23 @@ object JavadocConfig { val encoding = Encoding("UTF-8") + /** + * Applies the Javadoc settings to the `javadoc` task of the given [project], + * or disables the task if the project is not a production module. + * + * The task must be registered. It is configured when Gradle creates it, + * so calling this function does not create the task. + */ fun applyTo(project: Project) { - val javadocTask = project.tasks.javadocTask() - if (!isProductionModule(project)) { - javadocTask.enabled = false - return + project.tasks.javadocTask().configure { + if (!isProductionModule(project)) { + enabled = false + return@configure + } + discardJavaModulesInLinks(this) + val docletOptions = options as StandardJavadocDocletOptions + configureDoclet(docletOptions) } - discardJavaModulesInLinks(javadocTask) - val docletOptions = javadocTask.options as StandardJavadocDocletOptions - configureDoclet(docletOptions) } private fun isProductionModule(project: Project) = project.run { diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtoExts.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtoExts.kt index fd5dba83fc..0ade0727b7 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtoExts.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/ProtoExts.kt @@ -20,6 +20,7 @@ import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.file.FileTreeElement import org.gradle.api.file.SourceDirectorySet +import org.gradle.api.tasks.TaskCollection import org.gradle.api.tasks.bundling.Jar /** @@ -67,15 +68,18 @@ internal fun FileTreeElement.isGoogleProtoSource(): Boolean { } /** - * The reference to the `generateProto` task of a `main` source set. + * The `generateProto` task of a `main` source set, found without creating it. + * + * The returned collection is live: it holds the task once it is registered, + * and stays empty in a project without Protobuf. */ -internal fun Project.generateProto(): Task? = tasks.findByName("generateProto") +internal fun Project.generateProto(): TaskCollection = + tasks.named { it == "generateProto" } /** - * Makes this [Jar] task depend on the [generateProto] task, if it exists in the same project. + * Makes this [Jar] task depend on the [generateProto] task, once that task is registered + * in the same project. */ internal fun Jar.dependOnGenerateProto() { - project.generateProto()?.let { - this.dependsOn(it) - } + this.dependsOn(project.generateProto()) } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt index 7d6cf7e998..d083018b97 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationChecksums.kt @@ -15,6 +15,7 @@ package io.spine.gradle.publish import io.spine.gradle.SpineTaskGroup +import io.spine.gradle.getOrRegister import java.io.File import java.security.MessageDigest import java.util.Locale @@ -98,6 +99,13 @@ internal object PublicationChecksums { * the root project of a multi-module build, which is where `publish.yml` * expects the manifest. A module configuring the extension for itself also * gets an aggregator of its own, describing only that module. + * + * The registration is idempotent. `spinePublishing { }` configures the extension + * anew on every call, and the same project can be reached by two such calls: + * the root extension lists a module in [SpinePublishing.modulesWithCustomPublishing], + * while the module itself opens the extension with `customPublishing = true` — + * which is what `uber-jar-module.gradle.kts` does. Plain registration would fail + * on the second call, during configuration. */ fun registerTasks(host: Project, published: Set) { val collectors = published.map { registerCollectorIn(it) } @@ -177,10 +185,10 @@ internal object PublicationChecksums { // build directory afterwards. // // The list belongs to the project rather than to this call, because the - // task is registered once while `registerTasks` may run several times — - // see `getOrRegister`. Were the action to close over one call's projects, - // a later call adding a module would register its collector and still - // leave it out of the manifest. + // task is registered once while `registerTasks` may run several times, as + // the documentation of `registerTasks` explains. Were the action to close + // over one call's projects, a later call adding a module would register its + // collector and still leave it out of the manifest. val sources = host.attestationSources() sources += published.map { collectorOutput(it) } val target = host.layout.buildDirectory.file(aggregatePath) @@ -256,27 +264,6 @@ internal object PublicationChecksums { } } -/** - * Returns the task named [name] in this container, registering it with [init] - * if it is not there yet. - * - * `spinePublishing { }` configures the extension anew on every call, and the - * same project can be reached by two such calls: the root extension lists a - * module in [SpinePublishing.modulesWithCustomPublishing], while the module - * itself opens the extension with `customPublishing = true` — which is what - * `uber-jar-module.gradle.kts` does. Plain registration fails on the second - * call, during configuration, so registration has to be idempotent. - */ -private fun TaskContainer.getOrRegister( - name: String, - init: Task.() -> Unit -): TaskProvider = - if (names.contains(name)) { - named(name) - } else { - register(name, init) - } - /** * Returns the `clean` task of this container, if it has one. * @@ -345,7 +332,7 @@ private fun Project.publishedArtifacts(): Map { */ private fun Project.pomFileOf(publication: MavenPublication): File? = tasks.withType(GenerateMavenPom::class.java) - .findByName("generatePomFileFor${publication.taskSuffix()}") + .findByName(publication.pomTaskName()) ?.destination ?.takeIf { it.exists() } @@ -390,6 +377,11 @@ private fun MavenPublication.rejectMavenSnapshot() { private fun MavenPublication.taskSuffix(): String = "${name.replaceFirstChar { it.titlecase(Locale.ROOT) }}Publication" +/** + * Returns the name of the task that writes the POM of this publication. + */ +internal fun MavenPublication.pomTaskName(): String = "generatePomFileFor${taskSuffix()}" + /** * Returns the SHA-256 digest of this file as a lowercase hexadecimal string. * diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt index e32c622fdf..64ea35ec76 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/PublicationSbom.kt @@ -154,7 +154,7 @@ internal object PublicationSbom { * Whether a project is a JVM or a multiplatform module is known only once it is * evaluated, so the registration waits until then. It is idempotent, because * `spinePublishing { }` may reach one project twice, as the documentation of - * `getOrRegister` in `PublicationChecksums.kt` explains. + * [PublicationChecksums.registerTasks] explains. */ fun registerTasks(host: Project, published: Set) { published.forEach { project -> diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt index 4af48a5633..31a7a9fcd4 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/SpinePublishing.kt @@ -17,6 +17,7 @@ package io.spine.gradle.publish import io.spine.dependency.local.Spine +import io.spine.gradle.github.pages.PublishAllApiDocs import io.spine.gradle.repo.Repository import java.util.Locale import org.gradle.api.Project @@ -332,6 +333,9 @@ open class SpinePublishing(private val project: Project) { // After `PublicationSbom`: its `projectsEvaluated` callback adds the SBOM artifacts // that the one of `PublicationState` collects. PublicationState.registerOn(project.rootProject) + // `publishAllApiDocs` is registered here, as this is where the published modules + // are known. It is not tied to `publish`: neither task depends on the other. + PublishAllApiDocs.registerIn(project.rootProject, projectsToPublish) } /** diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt index f17170a071..030d03470c 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/StandardJavaPublicationHandler.kt @@ -17,9 +17,11 @@ package io.spine.gradle.publish import io.spine.gradle.repo.Repository import org.gradle.api.Project import org.gradle.api.publish.maven.MavenPublication +import org.gradle.api.publish.maven.tasks.GenerateMavenPom import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Jar import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.withType /** * A publication for a typical Java project. @@ -58,6 +60,12 @@ class StandardJavaPublicationHandler private constructor( */ const val PUBLICATION_NAME = "mavenJava" + /** + * The packaging of a POM whose main artifact is a JAR, + * and the extension of that artifact. + */ + private const val JAR = "jar" + override fun create( project: Project, destinations: Set, @@ -108,6 +116,7 @@ class StandardJavaPublicationHandler private constructor( val javaComponent = project.components.findByName("java") javaComponent?.let { from(it) + declareJarPackaging() } /* @@ -118,4 +127,63 @@ class StandardJavaPublicationHandler private constructor( artifact(it) } } + + /** + * Sets the `jar` packaging of the POM, which Gradle would calculate from + * the JAR of the `java` component. + * + * Until the packaging is set, reading it makes Gradle calculate it from the artifacts + * of the publication, which creates the tasks producing them. [PublicationSbom] reads + * the packaging in every build, so that the SBOM it adds does not change it. + * + * Writing the POM fails if the publication turns out to have a main artifact other + * than one JAR, so that a misleading POM is not published. The artifacts are checked + * when the POM is written, so that the check neither creates the tasks producing them + * nor takes the artifacts of the component into the publication before it is final. + * The result is an input of the task, so an up-to-date task does not hide a mismatch. + */ + private fun MavenPublication.declareJarPackaging() { + pom.packaging = JAR + val publication = this + val pomTask = pomTaskName() + project.tasks.withType() + .named { it == pomTask } + .configureEach { + val mismatch = project.provider { publication.jarPackagingMismatch() } + inputs.property("jarPackagingMismatch", mismatch.orElse("")) + doFirst { + mismatch.orNull?.let { throw IllegalStateException(it) } + } + } + } + + /** + * Describes how this publication contradicts the `jar` packaging, or returns `null` + * if it does not. + * + * The publication contradicts it if it keeps the `jar` packaging, but does not have + * exactly one main artifact, a JAR, the SBOM not counted. Such is the case if + * the build gives the `jar` task a classifier, or adds an artifact without one. + */ + private fun MavenPublication.jarPackagingMismatch(): String? { + if (pom.packaging != JAR) { + // The build has set a packaging of its own. + return null + } + val mainArtifacts = artifacts.filter { + it.classifier.isNullOrEmpty() && it.extension != PublicationSbom.sbomExtension + } + return if (mainArtifacts.singleOrNull()?.extension == JAR) { + null + } else { + val found = if (mainArtifacts.isEmpty()) { + "no main artifact" + } else { + "the main artifacts ${mainArtifacts.map { it.file.name }}" + } + "The POM of the `$name` publication of `${project.path}` declares the `jar`" + + " packaging, but the publication has $found. Please keep the `jar`" + + " task without a classifier, or publish the module with custom publishing." + } + } } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/LicenseReporter.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/LicenseReporter.kt index 65d8d69a14..c2af416980 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/license/LicenseReporter.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/license/LicenseReporter.kt @@ -20,7 +20,6 @@ import com.github.jk1.license.LicenseReportPlugin import io.spine.dependency.local.Spine import io.spine.gradle.SpineTaskGroup import io.spine.gradle.applyPlugin -import io.spine.gradle.getTask import io.spine.gradle.report.license.Paths.outputFilename import io.spine.gradle.report.license.Paths.relativePath import java.io.File @@ -130,10 +129,13 @@ object LicenseReporter { group = SpineTaskGroup.name description = "Merges per-project license reports into a single repository-wide report" val consolidationTask = this - val assembleTask = project.getTask("assemble") + val assembleTask = project.tasks.named("assemble") val sourceProjects: Iterable = sourceProjects(rootProject) sourceProjects.forEach { - val perProjectTask = it.getTask(projectTaskName) + // Obtained rather than configured lazily: in a single-project build, this + // action belongs to the container that holds the task, and Gradle forbids + // configuring a task of a container from such an action. + val perProjectTask = it.tasks.named(projectTaskName).get() consolidationTask.dependsOn(perProjectTask) perProjectTask.dependsOn(assembleTask) } @@ -142,8 +144,9 @@ object LicenseReporter { } dependsOn(assembleTask) } - project.getTask("build") - .finalizedBy(mergeTask) + project.tasks.named("build").configure { + finalizedBy(mergeTask) + } } /** diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomGenerator.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomGenerator.kt index 479e4f5f20..234a3af44f 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomGenerator.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/PomGenerator.kt @@ -100,11 +100,9 @@ object PomGenerator { writer.writeTo(pomFile) } - val assembleTask = project.tasks.findByName("assemble")!! - dependsOn(assembleTask) + dependsOn(project.tasks.named("assemble")) } - val buildTask = project.tasks.findByName("build")!! - buildTask.finalizedBy(task) + project.tasks.named("build").configure { finalizedBy(task) } } } diff --git a/buildSrc/src/main/kotlin/jvm-module.gradle.kts b/buildSrc/src/main/kotlin/jvm-module.gradle.kts index 830335fbd8..11777117af 100644 --- a/buildSrc/src/main/kotlin/jvm-module.gradle.kts +++ b/buildSrc/src/main/kotlin/jvm-module.gradle.kts @@ -26,7 +26,7 @@ import io.spine.dependency.local.Reflect import io.spine.dependency.test.Jacoco import io.spine.gradle.SpineTaskGroup import io.spine.gradle.checkstyle.CheckStyleConfig -import io.spine.gradle.github.pages.updateGitHubPages +import io.spine.gradle.github.pages.publishApiDocs import io.spine.gradle.javac.configureErrorProne import io.spine.gradle.javac.configureJavac import io.spine.gradle.javadoc.JavadocConfig @@ -58,7 +58,7 @@ project.run { val generatedDir = "$projectDir/generated" setTaskDependencies(generatedDir) - configureGitHubPages() + configureApiDocs() } typealias Module = Project @@ -150,19 +150,21 @@ fun Module.setTaskDependencies(generatedDir: String) { clean.configure { dependsOn(cleanGenerated) } - - project.afterEvaluate { - val publish = tasks.findByName("publish") - publish?.dependsOn("${project.path}:updateGitHubPages") - } } afterEvaluate { configureTaskDependencies() } } -fun Module.configureGitHubPages() { - updateGitHubPages { +/** + * Applies the plugin that registers the `publishApiDocs` task of this module. + * + * The `publish-api-docs.yml` workflow runs the task through `publishAllApiDocs` of + * the root project, which depends on it for the published modules only. It is not + * a part of `publish`. + */ +fun Module.configureApiDocs() { + publishApiDocs { rootFolder.set(rootDir) } } diff --git a/buildSrc/src/main/kotlin/module.gradle.kts b/buildSrc/src/main/kotlin/module.gradle.kts index bf1eab838b..f7018cb3ff 100644 --- a/buildSrc/src/main/kotlin/module.gradle.kts +++ b/buildSrc/src/main/kotlin/module.gradle.kts @@ -33,7 +33,7 @@ import io.spine.dependency.local.Base import io.spine.dependency.local.CoreJvm import io.spine.dependency.local.ToolBase import io.spine.dependency.local.Validation -import io.spine.gradle.github.pages.updateGitHubPages +import io.spine.gradle.github.pages.publishApiDocs import io.spine.gradle.javac.configureErrorProne import io.spine.gradle.javac.configureJavac import io.spine.gradle.javadoc.JavadocConfig @@ -150,11 +150,7 @@ fun Module.configureKotlin() { * Configures documentation publishing for this subproject. */ fun Module.setupDocPublishing() { - updateGitHubPages { + publishApiDocs { rootFolder.set(rootDir) } - - tasks.named("publish") { - dependsOn("${project.path}:updateGitHubPages") - } } diff --git a/buildSrc/src/test/kotlin/BuildExtensionsSpec.kt b/buildSrc/src/test/kotlin/BuildExtensionsSpec.kt new file mode 100644 index 0000000000..4ac7a55670 --- /dev/null +++ b/buildSrc/src/test/kotlin/BuildExtensionsSpec.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import org.gradle.api.DefaultTask +import org.gradle.api.InvalidUserDataException +import org.gradle.api.Project +import org.gradle.api.tasks.JavaExec +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test + +@DisplayName("Build extensions should") +internal class BuildExtensionsSpec { + + private val project: Project = ProjectBuilder.builder().build() + + @Nested inner class + `set remote debug options` { + + @Test + fun `on a JavaExec task once it is created`() { + project.tasks.register("launch", JavaExec::class.java) + + project.setRemoteDebug("launch") + + val debug = project.tasks.named("launch", JavaExec::class.java).get().debugOptions + debug.enabled.get() shouldBe true + debug.port.get() shouldBe BuildSettings.REMOTE_DEBUG_PORT + } + + @Test + fun `without creating the task`() { + var created = false + project.tasks.register("launch", JavaExec::class.java) { created = true } + + project.setRemoteDebug("launch") + + created shouldBe false + } + + @Test + fun `failing at once for a missing task`() { + shouldThrow { + project.setRemoteDebug("missing") + } + } + + @Test + fun `failing at once for a task other than JavaExec`() { + var created = false + project.tasks.register("plain", DefaultTask::class.java) { created = true } + + shouldThrow { + project.setRemoteDebug("plain") + } + created shouldBe false + } + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/CliSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/CliSpec.kt new file mode 100644 index 0000000000..69f03ba85b --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/CliSpec.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.gradle + +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import java.io.File +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +@DisplayName("`Cli` should") +internal class CliSpec { + + @TempDir + lateinit var workingFolder: File + + @Test + fun `return the output as the command wrote it, line breaks included`() { + // `printf` turns the `\n` sequences of its format into line breaks. + Cli(workingFolder).execute("printf", "one\\ntwo\\n") shouldBe "one\ntwo\n" + } + + @Test + fun `run a command assembled as a list`() { + Cli(workingFolder).execute(listOf("printf", "%s", "one")) shouldBe "one" + } + + @Test + fun `fail with the exit code and the error output of a failed command`() { + val error = shouldThrow { + Cli(workingFolder).execute("sh", "-c", "echo 'went wrong' >&2; exit 3") + } + + error.message shouldContain "exit code 3" + error.message shouldContain "went wrong" + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/docs/DokkaSetupIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/docs/DokkaSetupIgTest.kt index 6ec5effe99..150fe348f3 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/docs/DokkaSetupIgTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/docs/DokkaSetupIgTest.kt @@ -52,7 +52,7 @@ private const val PROBE_PATH = ":dokka-sample:dokkaGeneratePublicationProbe" * The build publishes a `javadocJar` that depends on the probe, just as the `javadocJar` * that `spinePublishing` creates depends on `dokkaGeneratePublicationJavadoc`. The build * publishes to a file-based repository and to its own Maven Local repository, so it never - * touches `~/.m2`. The `updateGitHubPages` task of the build stands in for the one that + * touches `~/.m2`. The `publishApiDocs` task of the build stands in for the one that * copies the Dokka output to GitHub Pages. * * The project with the probe is named `dokka-sample`, like the modules of `dokka-tools`, @@ -105,10 +105,10 @@ internal class DokkaSetupIgTest { } @Test - fun `run a Dokka task when the build updates GitHub Pages and publishes to Maven Local`() { + fun `run a Dokka task when the build publishes the API docs and publishes to Maven Local`() { runStoringThenReusing( ":dokka-sample:publishToMavenLocal", - ":dokka-sample:updateGitHubPages" + ":dokka-sample:publishApiDocs" ) { it.probeOutcome shouldBe SUCCESS } @@ -227,7 +227,7 @@ internal class DokkaSetupIgTest { } } - tasks.register("updateGitHubPages") { + tasks.register("publishApiDocs") { dependsOn(docsProbe) } """.trimIndent() diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/git/RepositorySpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/git/RepositorySpec.kt new file mode 100644 index 0000000000..e84919f555 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/git/RepositorySpec.kt @@ -0,0 +1,313 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.gradle.git + +import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.file.shouldExist +import io.kotest.matchers.file.shouldNotExist +import io.kotest.matchers.shouldBe +import io.spine.gradle.Cli +import io.spine.gradle.github.pages.docsCheckoutPatterns +import java.io.File +import org.gradle.api.Project +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * Verifies a [sparse clone][Repository.Factory.cloneSparsely] against a local bare + * repository, reached by a `file:` URL the way Git reaches a remote one: with a plain + * path, Git would ignore `--depth` and `--filter`. + * + * The `gh-pages` branch of the repository holds a top-level `CNAME`, the documentation + * of the module `m`, with the folders of its versions `1.0.0` and `1.1.0` and a file + * next to them, and the documentation of the module `other`. The tests check out + * the paths that [docsCheckoutPatterns] selects for `m`. + */ +@DisplayName("A sparse clone of a `Repository` should") +internal class RepositorySpec { + + @TempDir + lateinit var tempDir: File + + private lateinit var remote: File + + /** A full clone of the [remote], standing in for the publications of other modules. */ + private lateinit var seed: File + + private lateinit var project: Project + + private val user = UserInfo("Docs Publisher", "docs@example.com") + + @BeforeEach + fun createRemote() { + remote = tempDir.resolve("remote.git") + git(tempDir, "init", "--bare", "--initial-branch=master", remote.path) + // Allow partial clones, with the blobs fetched on demand, as GitHub does. + git(remote, "config", "uploadpack.allowFilter", "true") + git(remote, "config", "uploadpack.allowAnySHA1InWant", "true") + + seed = tempDir.resolve("seed") + git(tempDir, "clone", remote.path, seed.path) + git(seed, "config", "user.name", "Seed") + git(seed, "config", "user.email", "seed@example.com") + seed.write("README.md", "The sources.") + seed.commit("Add the sources.") + git(seed, "push", "origin", "HEAD:refs/heads/master") + + git(seed, "switch", "--orphan", "gh-pages") + seed.write("CNAME", "spine.io\n") + seed.write("javadoc/m/index.html", "m, 1.1.0") + seed.write("javadoc/m/v/1.0.0/index.html", "m, 1.0.0") + seed.write("javadoc/m/v/1.1.0/index.html", "m, 1.1.0") + seed.write("javadoc/m/v/notes.txt", "Not a version.") + seed.write("javadoc/other/index.html", "other, 1.1.0") + seed.commit("Publish the documentation.") + git(seed, "push", "origin", "gh-pages") + + project = ProjectBuilder.builder() + .withProjectDir(tempDir.resolve("project")) + .build() + } + + @Test + fun `check out only the top-level files`() { + cloneDocs().use { repo -> + val root = repo.location.toFile() + + root.resolve("CNAME").shouldExist() + root.resolve("javadoc").shouldNotExist() + } + } + + @Test + fun `check out only the paths of a publication`() { + cloneDocs().use { repo -> + repo.checkOutOnly(docsCheckoutPatterns("javadoc/m", "2.0.0")) + val root = repo.location.toFile() + + root.resolve("javadoc/m/index.html").shouldExist() + root.resolve("javadoc/m/v/1.0.0").shouldNotExist() + root.resolve("javadoc/other").shouldNotExist() + } + } + + /** + * Publishing a version again, as a re-run of a failed publication does, writes + * into the folder of that version, which is in the branch already. + */ + @Test + fun `check out and update the folder of a version published before`() { + cloneDocs().use { repo -> + repo.checkOutOnly(docsCheckoutPatterns("javadoc/m", "1.1.0")) + val root = repo.location.toFile() + + root.resolve("javadoc/m/v/1.1.0/index.html").shouldExist() + root.resolve("javadoc/m/v/1.0.0").shouldNotExist() + + root.write("javadoc/m/v/1.1.0/index.html", "m, 1.1.0, again") + repo.commitAllChanges("Publish `m` 1.1.0 again.") + + changedPaths(root) shouldContainExactly listOf("M\tjavadoc/m/v/1.1.0/index.html") + } + } + + @Test + fun `list the folders that are not checked out, without the files`() { + cloneDocs().use { repo -> + repo.listFolders("javadoc/m/v") shouldContainExactly listOf("1.0.0", "1.1.0") + repo.listFolders("javadoc/absent").shouldBeEmpty() + } + } + + @Test + fun `commit only the changed paths, keeping those not checked out`() { + cloneDocs().use { repo -> + repo.checkOutOnly(docsCheckoutPatterns("javadoc/m", "2.0.0")) + val root = repo.location.toFile() + root.write("javadoc/m/index.html", "m, 2.0.0") + root.write("javadoc/m/v/2.0.0/index.html", "m, 2.0.0") + + repo.commitAllChanges("Publish `m` 2.0.0.") + + changedPaths(root) shouldContainExactlyInAnyOrder listOf( + "M\tjavadoc/m/index.html", + "A\tjavadoc/m/v/2.0.0/index.html" + ) + } + } + + @Test + fun `push onto a commit that another publication pushed meanwhile`() { + cloneDocs().use { repo -> + repo.checkOutOnly(docsCheckoutPatterns("javadoc/m", "2.0.0")) + repo.location.toFile().write("javadoc/m/v/2.0.0/index.html", "m, 2.0.0") + repo.commitAllChanges("Publish `m` 2.0.0.") + + seed.write("javadoc/other/index.html", "other, 2.0.0") + seed.commit("Publish `other` 2.0.0.") + git(seed, "push", "origin", "gh-pages") + + repo.push() + } + + val log = git(remote, "log", "--format=%s", "gh-pages").lines() + log shouldContain "Publish `m` 2.0.0." + log shouldContain "Publish `other` 2.0.0." + git(remote, "show", "gh-pages:javadoc/m/v/2.0.0/index.html") shouldBe "m, 2.0.0" + git(remote, "show", "gh-pages:javadoc/other/index.html") shouldBe "other, 2.0.0" + git(remote, "show", "gh-pages:javadoc/m/v/1.0.0/index.html") shouldBe "m, 1.0.0" + } + + @Test + fun `create a branch that does not exist yet, and push to it`() { + val cname = "spine.io\n" + + cloneSite(initialFiles = mapOf("CNAME" to cname)).use { repo -> + git(remote, "ls-tree", "--name-only", "site").trim() shouldBe "CNAME" + git(remote, "show", "site:CNAME") shouldBe cname + + repo.checkOutOnly(docsCheckoutPatterns("javadoc/m", "1.0.0")) + repo.location.toFile().write("javadoc/m/index.html", "m, 1.0.0") + repo.commitAllChanges("Publish `m` 1.0.0.") + repo.push() + } + + git(remote, "show", "site:javadoc/m/index.html") shouldBe "m, 1.0.0" + } + + @Test + fun `adopt a branch that another publication created first, and push to it`() { + val preparedCommit = raceForSiteBranch() + + cloneSite(initialFiles = mapOf("CNAME" to "spine.io\n")).use { repo -> + val root = repo.location.toFile() + git(root, "rev-parse", "HEAD").trim() shouldBe preparedCommit + git(root, "rev-parse", "--abbrev-ref", "site@{upstream}").trim() shouldBe + "origin/site" + + raceHook.delete() + repo.checkOutOnly(docsCheckoutPatterns("javadoc/m", "1.0.0")) + root.write("javadoc/m/index.html", "m, 1.0.0") + repo.commitAllChanges("Publish `m` 1.0.0.") + repo.push() + } + + git(remote, "show", "site:javadoc/m/index.html") shouldBe "m, 1.0.0" + } + + /** + * The full [clone][Repository.Factory.clone] shares the adoption of a branch with + * the sparse one. + */ + @Test + fun `adopt a branch that another publication created first, in a full clone`() { + val preparedCommit = raceForSiteBranch() + + Repository.clone( + project, + sshUrl = url, + user = user, + branch = "site", + initialFiles = mapOf("CNAME" to "spine.io\n") + ).use { repo -> + val root = repo.location.toFile() + git(root, "rev-parse", "HEAD").trim() shouldBe preparedCommit + git(root, "rev-parse", "--abbrev-ref", "site@{upstream}").trim() shouldBe + "origin/site" + } + } + + /** + * Makes another publication create the `site` branch after this one has found it + * missing, and push first. + * + * The `pre-receive` hook of the [remote] stands in for that publication: it creates + * the branch from a prepared commit, and rejects the push of this publication. + * + * @return the prepared commit. + */ + private fun raceForSiteBranch(): String { + git(seed, "switch", "--orphan", "prepared") + seed.write("CNAME", "spine.io\n") + seed.commit("Initialize the `site` branch.") + git(seed, "push", "origin", "prepared:refs/heads/prepared-site") + // Git keeps the objects a push brings in a quarantine until the hook accepts + // them, and refuses to update a reference from there, so the hook leaves it. + raceHook.apply { + writeText( + """ + #!/bin/sh + env -u GIT_QUARANTINE_PATH -u GIT_OBJECT_DIRECTORY \ + -u GIT_ALTERNATE_OBJECT_DIRECTORIES \ + git update-ref refs/heads/site refs/heads/prepared-site + exit 1 + """.trimIndent() + ) + setExecutable(true) + } + return git(seed, "rev-parse", "HEAD").trim() + } + + private val raceHook: File + get() = remote.resolve("hooks/pre-receive") + + private val url: String + get() = remote.toPath().toUri().toString() + + /** + * Obtains the paths the last commit in the [root] of a clone changed, each + * with the letter of its change. + */ + private fun changedPaths(root: File): List = + git(root, "show", "--name-status", "--format=", "HEAD") + .lines() + .filter { it.isNotBlank() } + + private fun cloneDocs(): Repository = + Repository.cloneSparsely(project, sshUrl = url, user = user, branch = "gh-pages") + + /** + * Clones the `site` branch, which the [remote] does not have at first. + */ + private fun cloneSite(initialFiles: Map): Repository = + Repository.cloneSparsely( + project, + sshUrl = url, + user = user, + branch = "site", + initialFiles = initialFiles + ) +} + +private fun git(directory: File, vararg arguments: String): String = + Cli(directory).execute("git", *arguments) + +private fun File.write(path: String, content: String) { + resolve(path).apply { + parentFile.mkdirs() + writeText(content) + } +} + +private fun File.commit(message: String) { + git(this, "add", "--all") + git(this, "commit", "--message=$message") +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/github/pages/NewestAboveSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/github/pages/NewestAboveSpec.kt new file mode 100644 index 0000000000..ad5f631703 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/github/pages/NewestAboveSpec.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.gradle.github.pages + +import io.kotest.matchers.nulls.shouldBeNull +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +/** + * Verifies how the publication of the API documentation decides whether the most + * recent documentation of a module may be replaced by that of the published version. + */ +@DisplayName("`newestAbove` should") +internal class NewestAboveSpec { + + @Test + fun `find no newer version when nothing is published`() { + emptyList().newestAbove("2.0.0").shouldBeNull() + } + + @Test + fun `find no newer version for the newest one`() { + listOf("1.9.0", "2.0.0-SNAPSHOT.575", "2.0.0-SNAPSHOT.99") + .newestAbove("2.0.0").shouldBeNull() + } + + @Test + fun `find no newer version for a version published again`() { + listOf("1.9.0", "2.0.0").newestAbove("2.0.0").shouldBeNull() + } + + @Test + fun `find the newest version above an older one`() { + listOf("1.9.0", "2.1.0", "2.0.0").newestAbove("1.9.5") shouldBe "2.1.0" + } + + @Test + fun `compare versions by their meaning rather than as text`() { + listOf("2.9.0").newestAbove("2.10.0").shouldBeNull() + listOf("2.10.0").newestAbove("2.9.0") shouldBe "2.10.0" + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/github/pages/PublishApiDocsIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/github/pages/PublishApiDocsIgTest.kt new file mode 100644 index 0000000000..9fc3a345f1 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/github/pages/PublishApiDocsIgTest.kt @@ -0,0 +1,349 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.gradle.github.pages + +import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.collections.shouldNotContain +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import java.io.File +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +/** + * Verifies which tasks the `publishAllApiDocs` task of the root project, registered by + * `spinePublishing { }`, brings into a build: the `publishApiDocs` tasks of the projects. + * + * The builds that would publish documentation run with `--dry-run`, so that nothing + * is pushed to GitHub Pages. The builds of a snapshot version run for real, as they + * publish nothing. + * + * In the multi-module build, `api` and `backend` are published and document + * themselves, `testing` documents itself, but is not published, as a module of + * integration tests, and `bare` is published, but does not document itself. + * + * No build applies Dokka. A task named like the Dokka one stands in for it, as + * the plugin and the `javadocJar` of `spinePublishing` look the task up by name. + */ +@DisplayName("`publishAllApiDocs` task should") +internal class PublishApiDocsIgTest { + + @TempDir + lateinit var projectDir: File + + @Test + fun `publish the docs of each published module that documents itself`() { + writeMultiModuleBuild(documented = setOf("api", "backend", "testing")) + + val planned = dryRun(":$aggregate") + + planned shouldContain ":$aggregate" + planned.docsTasks() shouldContainExactlyInAnyOrder listOf( + ":api:$taskName", + ":backend:$taskName" + ) + // `testing` has the task, so the aggregate left it out only for not being published. + dryRun(":testing:$taskName").docsTasks() shouldBe listOf(":testing:$taskName") + } + + /** + * `lib` opens `spinePublishing { }` on its own, so the second call reaches + * the task of the root project while `lib` is evaluated, with projects of its own. + */ + @Test + fun `publish the docs of a module that configures its own publishing`() { + file("settings.gradle.kts").writeText( + """ + rootProject.name = "own-publishing-sample" + include("api", "lib") + """.trimIndent() + ) + file("build.gradle.kts").writeText( + """ + ${buildscript()} + + import io.spine.gradle.github.pages.publishApiDocs + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "io.spine.sample" + version = "1.0.0" + } + + subprojects { + apply(plugin = "java-library") + $generatorStub + } + + project("api").publishApiDocs { + rootFolder.set(rootDir) + } + + spinePublishing { + modules = setOf("api") + destinations = emptySet() + } + """.trimIndent() + ) + file("lib/build.gradle.kts").apply { + parentFile.mkdirs() + writeText( + """ + import io.spine.gradle.github.pages.publishApiDocs + import io.spine.gradle.publish.spinePublishing + + publishApiDocs { + rootFolder.set(rootDir) + } + + spinePublishing { + destinations = emptySet() + } + """.trimIndent() + ) + } + file("api").mkdirs() + + dryRun(":$aggregate").docsTasks() shouldContainExactlyInAnyOrder listOf( + ":api:$taskName", + ":lib:$taskName" + ) + } + + @Test + fun `not be a part of the publication to Maven repositories`() { + writeMultiModuleBuild(documented = setOf("api", "backend", "testing")) + + val planned = dryRun("publish") + + planned shouldContain ":api:publish" + planned shouldNotContain ":$aggregate" + planned.docsTasks().shouldBeEmpty() + } + + @Test + fun `do nothing in a build that documents no module`() { + writeMultiModuleBuild(documented = emptySet()) + + val result = runner(":$aggregate").build() + + result.tasks.map { it.path } shouldBe listOf(":$aggregate") + result.task(":$aggregate")?.outcome shouldBe TaskOutcome.UP_TO_DATE + } + + @Test + fun `publish the docs of the project in a single-project build`() { + writeSingleProjectBuild(version = "1.0.0") + + val planned = dryRun(":$aggregate") + + planned.docsTasks() shouldBe listOf(":$taskName") + planned shouldContain ":${TaskName.copyJavadocDocs}" + } + + @Test + fun `publish no docs of a snapshot version`() { + writeMultiModuleBuild(documented = setOf("api", "backend", "testing"), version = snapshot) + + val result = runner(":$aggregate").build() + + val paths = result.tasks.map { it.path } + paths.docsTasks() shouldContainExactlyInAnyOrder listOf( + ":api:$taskName", + ":backend:$taskName" + ) + paths shouldNotContain ":api:${TaskName.copyJavadocDocs}" + result.output shouldContain "`$snapshot` is a snapshot version" + } + + /** + * Only the publication to GitHub Pages skips a snapshot version. The archives of + * its documentation, built by Dokka, are still published to Maven repositories. + */ + @Test + fun `leave the docs archives of a snapshot version to the Maven publication`() { + writeMultiModuleBuild(documented = setOf("api"), version = snapshot) + file("build.gradle.kts").appendText( + "\n" + """ + project("api") { + apply(plugin = "maven-publish") + the().repositories.maven { + name = "remote" + url = uri(rootDir.resolve("remote-repo")) + } + } + """.trimIndent() + ) + + val planned = dryRun(":api:publish") + + planned shouldContain ":api:javadocJar" + planned shouldContain ":api:dokkaGeneratePublicationJavadoc" + planned.docsTasks().shouldBeEmpty() + } + + @Test + fun `publish no docs of a snapshot version in a single-project build`() { + writeSingleProjectBuild(version = snapshot) + + val result = runner(":$aggregate").build() + + result.tasks.map { it.path } shouldContainExactlyInAnyOrder listOf( + ":$taskName", + ":$aggregate" + ) + result.output shouldContain "`$snapshot` is a snapshot version" + } + + private fun writeSingleProjectBuild(version: String) { + file("settings.gradle.kts").writeText("""rootProject.name = "single-sample"""") + file("build.gradle.kts").writeText( + """ + ${buildscript()} + + import io.spine.gradle.github.pages.publishApiDocs + import io.spine.gradle.publish.spinePublishing + + group = "io.spine.sample" + version = "$version" + + apply(plugin = "java-library") + $generatorStub + + publishApiDocs { + rootFolder.set(rootDir) + } + + spinePublishing { + destinations = emptySet() + } + """.trimIndent() + ) + } + + private fun writeMultiModuleBuild(documented: Set, version: String = "1.0.0") { + val modules = listOf("api", "backend", "bare", "testing") + modules.forEach { file(it).mkdirs() } + file("settings.gradle.kts").writeText( + """ + rootProject.name = "docs-sample" + include(${modules.joinToString { "\"$it\"" }}) + """.trimIndent() + ) + file("build.gradle.kts").writeText( + """ + ${buildscript()} + + import io.spine.gradle.github.pages.publishApiDocs + import io.spine.gradle.publish.spinePublishing + + allprojects { + group = "io.spine.sample" + version = "$version" + } + + subprojects { + apply(plugin = "java-library") + $generatorStub + } + + listOf(${documented.joinToString { "\"$it\"" }}).forEach { + project(it).publishApiDocs { + rootFolder.set(rootDir) + } + } + + spinePublishing { + modules = setOf("api", "backend", "bare") + destinations = emptySet() + } + """.trimIndent() + ) + } + + /** + * Runs the build with `--dry-run` and returns the paths of the tasks + * it would run. + * + * TestKit reports no tasks for a dry run, so they are read from the output, + * which lists each of them as ` SKIPPED`. + */ + private fun dryRun(task: String): List = + runner(task, "--dry-run").build().output.lines() + .filter { it.startsWith(":") && it.endsWith(" SKIPPED") } + .map { it.substringBefore(' ') } + + private fun runner(vararg args: String): GradleRunner = + GradleRunner.create() + .withProjectDir(projectDir) + .withArguments(*args, "--stacktrace") + + /** + * Selects the paths of the tasks that publish documentation. + */ + private fun List.docsTasks(): List = + filter { it.substringAfterLast(':') == taskName } + + private fun file(relativePath: String): File = projectDir.resolve(relativePath) + + private fun buildscript(): String = + """ + buildscript { + dependencies { + classpath(files( + ${buildSrcClasspath()} + )) + } + } + """.trimIndent() + + /** + * Renders the classpath with the production classes of `buildSrc` as + * arguments of `files(...)`, for injection into the build script classpath + * of the generated build. + * + * The classpath comes from the `test` task in `buildSrc/build.gradle.kts`. + */ + private fun buildSrcClasspath(): String { + val classpath = requireNotNull(System.getProperty("buildSrc.classpath")) { + "The `buildSrc.classpath` system property is not set." + + " It is supplied by the `test` task in `buildSrc/build.gradle.kts`." + } + return classpath.split(File.pathSeparator).joinToString(",\n") { + " \"${File(it).invariantSeparatorsPath}\"" + } + } + + private companion object { + + const val taskName = TaskName.publishApiDocs + + const val aggregate = TaskName.publishAllApiDocs + + /** A version in the format the Spine SDK publishes from every merge. */ + const val snapshot = "1.0.0-SNAPSHOT.1" + + /** + * A task standing in for the Dokka one whose output the plugin copies, and on + * which the `javadocJar` of `spinePublishing` depends. + */ + const val generatorStub = """tasks.register("dokkaGeneratePublicationJavadoc")""" + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/javadoc/JavadocConfigSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/javadoc/JavadocConfigSpec.kt new file mode 100644 index 0000000000..19b9e97316 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/javadoc/JavadocConfigSpec.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.gradle.javadoc + +import io.kotest.matchers.shouldBe +import org.gradle.api.Project +import org.gradle.api.plugins.JavaPlugin +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`JavadocConfig` should") +internal class JavadocConfigSpec { + + private val project: Project = ProjectBuilder.builder().build().also { + it.pluginManager.apply(JavaPlugin::class.java) + } + + /** + * The project of a build without subprojects is not a production module, + * so its `javadoc` task is disabled. + */ + @Test + fun `configure the javadoc task once Gradle creates it`() { + var created = false + project.tasks.named { it == "javadoc" }.configureEach { created = true } + + JavadocConfig.applyTo(project) + + created shouldBe false + project.tasks.javadocTask().get().enabled shouldBe false + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtoExtsSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtoExtsSpec.kt new file mode 100644 index 0000000000..3859d28ab3 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/ProtoExtsSpec.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2026 CodeMatters, Lda. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package io.spine.gradle.publish + +import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.shouldBe +import org.gradle.api.Project +import org.gradle.api.plugins.BasePlugin +import org.gradle.api.tasks.bundling.Jar +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("Proto extensions should") +internal class ProtoExtsSpec { + + private val project: Project = ProjectBuilder.builder().build().also { + it.pluginManager.apply(BasePlugin::class.java) + } + + private val jar: Jar = project.tasks.register("protoJar", Jar::class.java).get() + + @Test + fun `make a JAR depend on generateProto registered later, without creating it`() { + jar.dependOnGenerateProto() + var created = false + project.tasks.register("generateProto") { created = true } + + created shouldBe false + jar.dependencyNames() shouldContainExactly listOf("generateProto") + } + + @Test + fun `add no dependency to a JAR in a project without generateProto`() { + jar.dependOnGenerateProto() + + jar.dependencyNames().shouldBeEmpty() + } + + private fun Jar.dependencyNames(): List = + taskDependencies.getDependencies(this).map { it.name } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationSbomIgTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationSbomIgTest.kt index d64306ebb6..60e0ff7445 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationSbomIgTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/PublicationSbomIgTest.kt @@ -30,6 +30,7 @@ import io.kotest.matchers.file.shouldNotExist import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldNotContain import java.io.File import java.util.jar.JarOutputStream @@ -199,6 +200,73 @@ internal class PublicationSbomIgTest { packagingOf("osgi", osgiBundle) shouldBe "bundle" } + /** + * Until the packaging of a POM is set, reading it creates the tasks that produce + * the artifacts of the publication. A standard publication sets its packaging + * as it is created, so a build that does not publish creates none of them. + * + * The init script reports the tasks created before the task graph is ready, which + * excludes those that the fixture creates later, to report the SBOMs. + */ + @Test + fun `create no archive task of a standard publication in a build that does not publish`() { + val initScript = file("report-created-tasks.gradle") + initScript.writeText( + """ + def graphReady = false + gradle.taskGraph.whenReady { graphReady = true } + allprojects { + tasks.configureEach { task -> + if (!graphReady) println("$createdPrefix${'$'}{task.path}") + } + } + """.trimIndent() + ) + val result = GradleRunner.create() + .withProjectDir(projectDir) + .withArguments("help", "--init-script", initScript.path, "--offline", "--stacktrace") + .build() + + val created = result.output.lines() + .filter { it.startsWith(createdPrefix) } + .map { it.removePrefix(createdPrefix) } + created shouldContain ":help" + created shouldNotContainAnyOf listOf("api", "impl").flatMap { module -> + listOf("jar", "sourcesJar", "javadocJar", "htmlDocsJar").map { ":$module:$it" } + } + } + + /** + * A standard publication declares the `jar` packaging before its artifacts are known, + * so writing its POM fails if the build gives the `jar` task a classifier, + * rather than publish a POM that names no main artifact. + * + * The case checks `StandardJavaPublicationHandler`, but shares the fixture of this + * class, whose `api` module is a standard publication with an SBOM. + * + * The build of the fixture has written the POM of `api` already. So the case also shows + * that the result of the check is an input of the task: without it, the task would be + * up to date, and skip the check. + */ + @Test + fun `fail to write the POM of a standard publication whose JAR is classified`() { + val script = file("api/build.gradle.kts") + val original = script.readText() + script.appendText("\ntasks.jar { archiveClassifier.set(\"plain\") }\n") + try { + val result = GradleRunner.create() + .withProjectDir(projectDir) + .withArguments(":api:${pomTaskOf("mavenJava")}", "--offline", "--stacktrace") + .buildAndFail() + + result.output shouldContain + "The POM of the `mavenJava` publication of `:api` declares the `jar`" + + " packaging, but the publication has no main artifact." + } finally { + script.writeText(original) + } + } + @Test fun `describe runtime dependencies only`() { val names = implSbom().packageNames() @@ -908,6 +976,9 @@ internal class PublicationSbomIgTest { /** Marks the lines in which the fixture reports the SBOMs of each publication. */ const val reportPrefix = "SBOM-REPORT " + /** Marks the lines in which an init script reports the tasks created. */ + const val createdPrefix = "CREATED-TASK " + /** The publication of a thin JAR with a hand-written POM. */ const val pluginJar = "pluginJar" diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/license/DependencyReportOutputTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/license/DependencyReportOutputTest.kt index a6213ab912..96f756d75d 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/report/license/DependencyReportOutputTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/license/DependencyReportOutputTest.kt @@ -74,6 +74,29 @@ class DependencyReportOutputTest { reportFile.readText() shouldBe "license report" } + /** + * In a build of one project, the report to merge is that of the root project, whose + * task is in the same task container as the merging task. + */ + @Test + fun `merge the license report of a single-project build`() { + project.pluginManager.apply(BasePlugin::class.java) + LicenseReporter.generateReportIn(project) + val sourceReport = project.layout.buildDirectory.asFile.get() + .resolve(Paths.relativePath) + .resolve(Paths.outputFilename) + sourceReport.parentFile.mkdirs() + sourceReport.writeText("license report") + + LicenseReporter.mergeAllReports(project) + + project.tasks.named("mergeAllLicenseReports").get() + .executeActions() + + val reportFile = projectDir.resolve("docs/dependencies/dependencies.md") + reportFile.readText() shouldBe "license report" + } + private fun subproject(name: String): Project { val subprojectDir = projectDir.resolve(name) subprojectDir.mkdirs() diff --git a/config b/config index ad3dff0890..363fc1da31 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit ad3dff0890c7716cbba3fe2ce17bf4fe5905a318 +Subproject commit 363fc1da3184d001361fa9c327929eb5e05fa673 From a94831c75bf21a9b610ce776b35e0dcab2b31861 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 19:51:31 +0000 Subject: [PATCH 07/14] Update local dependency pins Restore ToolBase `2.0.0-SNAPSHOT.430`, which `./config/pull` reverted to `.428`. The Compiler does not call the lazy compile-task API added in `.430`: the CoreJvm Compiler fat JAR on the build-script classpath of consumers bundles an older ToolBase, which would fail such calls with `NoSuchMethodError`. Co-Authored-By: Claude Opus 5.5 --- buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt index 905ab2d0d6..bec332db0c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt @@ -32,7 +32,7 @@ package io.spine.dependency.local ) object ToolBase { const val group = Spine.toolsGroup - const val version = "2.0.0-SNAPSHOT.428" + const val version = "2.0.0-SNAPSHOT.430" const val dogfoodingVersion = "2.0.0-SNAPSHOT.428" const val archive = "$group:archive:$version" From 74e7b989d19eac3d2f0fcafcdf8c51a91884b250 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 19:51:39 +0000 Subject: [PATCH 08/14] Keep the `pom` packaging of the `protoc-plugin` POM The `jar` task of `protoc-plugin` has the `exe` classifier, so its publication has no main artifact, and Gradle has derived the `pom` packaging for its POM. `spinePublishing` now declares the `jar` packaging for standard publications and fails writing a POM whose publication has no main JAR (config#821). Restore the packaging published so far. Co-Authored-By: Claude Opus 5.5 --- protoc-plugin/build.gradle.kts | 39 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/protoc-plugin/build.gradle.kts b/protoc-plugin/build.gradle.kts index 9e5e992b28..de968153ff 100644 --- a/protoc-plugin/build.gradle.kts +++ b/protoc-plugin/build.gradle.kts @@ -1,32 +1,21 @@ /* - * Copyright 2026, TeamDev. All rights reserved. + * Copyright 2026 CodeMatters, Lda. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * - * Redistribution and use in source and/or binary forms, with or without - * modification, must retain the above copyright notice and the following - * disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. */ import io.spine.dependency.lib.Protobuf import io.spine.dependency.local.Base import io.spine.dependency.local.ToolBase +import io.spine.gradle.publish.StandardJavaPublicationHandler import org.gradle.api.file.DuplicatesStrategy.INCLUDE plugins { @@ -65,3 +54,15 @@ tasks.jar { archiveClassifier.set("exe") duplicatesStrategy = INCLUDE } + +// With the classifier above, the publication has no main artifact, so its POM keeps +// the `pom` packaging Gradle has always derived for it, rather than the `jar` packaging +// which `spinePublishing` declares for standard publications. +// The publication is created on `afterEvaluate` scheduled by the root project, +// so this action, scheduled later, finds it. +afterEvaluate { + the().publications + .named(StandardJavaPublicationHandler.PUBLICATION_NAME) { + pom.packaging = "pom" + } +} From 8be1fd5c40bca6b647f37bb104e04fd39b25341e Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Thu, 29 Oct 2026 19:51:47 +0000 Subject: [PATCH 09/14] Update dependency reports Co-Authored-By: Claude Opus 5.5 --- docs/dependencies/dependencies.md | 577 ++++-------------------------- docs/dependencies/pom.xml | 48 +-- 2 files changed, 89 insertions(+), 536 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index 7b00c65f37..3d6b80df43 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -560,7 +560,7 @@ * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -587,7 +587,7 @@ * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -605,7 +605,7 @@ * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -617,19 +617,19 @@ * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -653,7 +653,7 @@ * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -720,7 +720,7 @@ * **Project URL:** [https://github.com/google/gson](https://github.com/google/gson) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.11. +1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.12. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -817,31 +817,16 @@ * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) @@ -888,11 +873,11 @@ * **License:** [http://www.debian.org/misc/bsd.license](http://www.debian.org/misc/bsd.license) * **License:** [BSD](http://www.debian.org/misc/bsd.license) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) @@ -1123,18 +1108,10 @@ * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -1143,10 +1120,6 @@ * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -1159,10 +1132,6 @@ * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -1171,10 +1140,6 @@ * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -1463,10 +1428,6 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1587,10 +1548,6 @@ * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test-junit5. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1860,7 +1817,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:39 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2136,18 +2093,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** Indiana University Extreme! Lab Software License * **License:** [Indiana University Extreme! Lab Software License](https://raw.githubusercontent.com/x-stream/mxparser/master/LICENSE.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -2156,10 +2105,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -2172,10 +2117,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -2184,10 +2125,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -2578,7 +2515,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:38 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3149,7 +3086,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3176,7 +3113,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3194,7 +3131,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3206,19 +3143,19 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3242,7 +3179,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3309,7 +3246,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://github.com/google/gson](https://github.com/google/gson) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.11. +1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.12. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3406,31 +3343,16 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) @@ -3477,11 +3399,11 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [http://www.debian.org/misc/bsd.license](http://www.debian.org/misc/bsd.license) * **License:** [BSD](http://www.debian.org/misc/bsd.license) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) @@ -3712,18 +3634,10 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -3732,10 +3646,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -3748,10 +3658,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -3760,10 +3666,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -4052,10 +3954,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4176,10 +4074,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test-junit5. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4449,7 +4343,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:39 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -5124,11 +5018,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5150,12 +5039,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) - * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5168,12 +5051,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) - * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5186,30 +5063,18 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) - * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) - * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5234,12 +5099,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) - * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5375,7 +5234,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/google/gson](https://github.com/google/gson) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.11. +1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.12. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5472,31 +5331,16 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) @@ -5547,18 +5391,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.97.0. - * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) - * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) - 1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.97.0. - * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) - * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) - 1. **Group** : com.sksamuel.aedile. **Name** : aedile-core. **Version** : 3.0.4. * **Project URL:** [https://www.github.com/sksamuel/aedile](https://www.github.com/sksamuel/aedile) * **License:** [The Apache 2.0 License](https://opensource.org/licenses/Apache-2.0) @@ -5786,18 +5622,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -5806,10 +5634,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -5822,10 +5646,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -5834,10 +5654,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -6131,10 +5947,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -6255,10 +6067,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test-junit5. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -6528,7 +6336,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:39 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -7549,18 +7357,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -7569,10 +7369,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -7585,10 +7381,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -7597,10 +7389,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -8277,7 +8065,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:38 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -9302,18 +9090,10 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -9322,10 +9102,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -9338,10 +9114,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -9350,10 +9122,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -10066,7 +9834,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:39 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -10672,11 +10440,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10698,12 +10461,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) - * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10716,12 +10473,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) - * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10734,30 +10485,18 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) - * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) - * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10782,12 +10521,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.2. - * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) - * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10855,7 +10588,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/google/gson](https://github.com/google/gson) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.11. +1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.12. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10952,31 +10685,16 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) @@ -11027,18 +10745,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.97.0. - * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) - * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) - 1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.97.0. - * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) - * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) - 1. **Group** : com.sksamuel.aedile. **Name** : aedile-core. **Version** : 3.0.4. * **Project URL:** [https://www.github.com/sksamuel/aedile](https://www.github.com/sksamuel/aedile) * **License:** [The Apache 2.0 License](https://opensource.org/licenses/Apache-2.0) @@ -11266,18 +10976,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -11286,10 +10988,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -11302,10 +11000,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -11314,10 +11008,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -11606,10 +11296,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -11730,10 +11416,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test-junit5. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12003,7 +11685,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:39 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -12570,7 +12252,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12597,7 +12279,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12615,7 +12297,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12627,19 +12309,19 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12663,7 +12345,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12730,7 +12412,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/google/gson](https://github.com/google/gson) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.11. +1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.12. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12827,31 +12509,16 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) @@ -12898,11 +12565,11 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [http://www.debian.org/misc/bsd.license](http://www.debian.org/misc/bsd.license) * **License:** [BSD](http://www.debian.org/misc/bsd.license) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) @@ -13133,18 +12800,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -13153,10 +12812,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -13169,10 +12824,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -13181,10 +12832,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -13465,10 +13112,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13589,10 +13232,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test-junit5. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13862,7 +13501,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:39 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -14270,18 +13909,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -14290,10 +13921,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -14306,10 +13933,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -14318,10 +13941,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -14764,7 +14383,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:38 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -15335,7 +14954,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -15362,7 +14981,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -15380,7 +14999,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -15392,19 +15011,19 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -15428,7 +15047,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -15499,7 +15118,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://github.com/google/gson](https://github.com/google/gson) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.11. +1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.12. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -15596,31 +15215,16 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) @@ -15667,11 +15271,11 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **License:** [http://www.debian.org/misc/bsd.license](http://www.debian.org/misc/bsd.license) * **License:** [BSD](http://www.debian.org/misc/bsd.license) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) @@ -16214,10 +15818,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -16338,10 +15938,6 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test-junit5. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -16611,7 +16207,7 @@ This report was generated on **Thu Oct 29 17:27:38 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:39 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -17283,7 +16879,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-bom](https://github.com/FasterXML/jackson-bom) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -17310,7 +16906,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-core. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-core](https://github.com/FasterXML/jackson-core) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -17328,7 +16924,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.core. **Name** : jackson-databind. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson](https://github.com/FasterXML/jackson) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -17340,19 +16936,19 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.dataformat. **Name** : jackson-dataformat-yaml. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-dataformats-text](https://github.com/FasterXML/jackson-dataformats-text) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-guava. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-datatypes-collections](https://github.com/FasterXML/jackson-datatypes-collections) * **License:** [https://www.apache.org/licenses/LICENSE-2.0.txt](https://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.datatype. **Name** : jackson-datatype-jdk8. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8](https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -17376,7 +16972,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.2. +1. **Group** : com.fasterxml.jackson.module. **Name** : jackson-module-parameter-names. **Version** : 2.22.3. * **Project URL:** [https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names](https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -17443,7 +17039,7 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/google/gson](https://github.com/google/gson) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.11. +1. **Group** : com.google.devtools.ksp. **Name** : com.google.devtools.ksp.gradle.plugin. **Version** : 2.3.12. * **Project URL:** [https://goo.gle/ksp](https://goo.gle/ksp) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -17540,31 +17136,16 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-java-util. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.0. - * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) - * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) - 1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) @@ -17611,11 +17192,11 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **License:** [http://www.debian.org/misc/bsd.license](http://www.debian.org/misc/bsd.license) * **License:** [BSD](http://www.debian.org/misc/bsd.license) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) -1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.97.0. +1. **Group** : com.palantir.javaformat. **Name** : palantir-java-format-spi. **Version** : 2.102.0. * **Project URL:** [https://github.com/palantir/palantir-java-format](https://github.com/palantir/palantir-java-format) * **License:** [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) @@ -17846,18 +17427,10 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://detekt.dev](https://detekt.dev) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-api. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-bom. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -17866,10 +17439,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-core. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -17882,10 +17451,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-kotlin](https://github.com/grpc/grpc-kotlin) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-protobuf. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -17894,10 +17459,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) -1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.83.1. - * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) - * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) - 1. **Group** : io.grpc. **Name** : grpc-stub. **Version** : 1.85.0. * **Project URL:** [https://github.com/grpc/grpc-java](https://github.com/grpc/grpc-java) * **License:** [Apache 2.0](https://opensource.org/licenses/Apache-2.0) @@ -18186,10 +17747,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-bom. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-build-tools-api. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -18310,10 +17867,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test. **Version** : 2.4.21. - * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) - * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-test-junit5. **Version** : 2.4.10. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -18583,6 +18136,6 @@ This report was generated on **Thu Oct 29 17:27:39 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 17:27:39 WET 2026** using +This report was generated on **Thu Oct 29 19:46:31 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index a10f0dcea9..37cd09a73e 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -122,25 +122,25 @@ all modules and does not describe the project structure per-subproject. io.spine spine-server - 2.0.0-SNAPSHOT.571 + 2.0.0-SNAPSHOT.577 compile io.spine spine-time - 2.0.0-SNAPSHOT.251 + 2.0.0-SNAPSHOT.253 compile io.spine spine-time-java - 2.0.0-SNAPSHOT.251 + 2.0.0-SNAPSHOT.253 compile io.spine spine-validation-jvm-runtime - 2.0.0-SNAPSHOT.464 + 2.0.0-SNAPSHOT.469 compile @@ -152,37 +152,37 @@ all modules and does not describe the project structure per-subproject. io.spine.tools code - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile io.spine.tools fs - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile io.spine.tools gradle-plugin-api - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile io.spine.tools java-code - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile io.spine.tools jvm-tools - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile io.spine.tools kotlin-code - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile @@ -194,19 +194,19 @@ all modules and does not describe the project structure per-subproject. io.spine.tools plugin-base - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile io.spine.tools proto-code - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile io.spine.tools protobuf-setup-plugins - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile @@ -218,19 +218,19 @@ all modules and does not describe the project structure per-subproject. io.spine.tools psi-java - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 compile io.spine.tools server-testlib - 2.0.0-SNAPSHOT.571 + 2.0.0-SNAPSHOT.577 compile org.jetbrains.kotlin kotlin-bom - 2.4.21 + 2.4.10 compile @@ -308,13 +308,13 @@ all modules and does not describe the project structure per-subproject. io.spine.tools plugin-testlib - 2.0.0-SNAPSHOT.428 + 2.0.0-SNAPSHOT.430 test io.spine.tools time-testlib - 2.0.0-SNAPSHOT.251 + 2.0.0-SNAPSHOT.253 test @@ -405,27 +405,27 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-cli-all - 2.0.0-SNAPSHOT.069 + 2.0.0-SNAPSHOT.081 io.spine.tools compiler-protoc-plugin - 2.0.0-SNAPSHOT.069 + 2.0.0-SNAPSHOT.081 io.spine.tools core-jvm-gradle-plugin - 2.0.0-SNAPSHOT.097 + 2.0.0-SNAPSHOT.099 io.spine.tools core-jvm-plugins - 2.0.0-SNAPSHOT.097 + 2.0.0-SNAPSHOT.099 io.spine.tools dokka-extensions - 2.0.0-SNAPSHOT.10 + 2.0.0-SNAPSHOT.12 io.spine.tools @@ -440,7 +440,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools validation-java-bundle - 2.0.0-SNAPSHOT.464 + 2.0.0-SNAPSHOT.469 org.jacoco From f026a0f1f3d5a016fdb177c28cad5a4de5523b5d Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 30 Oct 2026 16:32:01 +0000 Subject: [PATCH 10/14] Update shared agent tooling and config (./config/pull) Co-Authored-By: Claude Opus 5.5 --- .github/workflows/publish.yml | 2 +- .../main/kotlin/io/spine/dependency/local/ToolBase.kt | 9 ++++++--- config | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4e1479a824..ba2a29ac66 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -30,7 +30,7 @@ on: jobs: publish: name: Publish to Maven repositories - uses: SpineEventEngine/config/.github/workflows/publishing.yml@363fc1da3184d001361fa9c327929eb5e05fa673 + uses: SpineEventEngine/config/.github/workflows/publishing.yml@ba47b5fb7a92ad1e5399c8714edd2160e0265a82 permissions: contents: read packages: write diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt index bec332db0c..7bd22c472a 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt @@ -32,7 +32,7 @@ package io.spine.dependency.local ) object ToolBase { const val group = Spine.toolsGroup - const val version = "2.0.0-SNAPSHOT.430" + const val version = "2.0.0-SNAPSHOT.428" const val dogfoodingVersion = "2.0.0-SNAPSHOT.428" const val archive = "$group:archive:$version" @@ -73,8 +73,11 @@ object ToolBase { const val gradlePluginApiTestFixtures = "$group:gradle-plugin-api-test-fixtures:$version" const val jvmTools = "$group:jvm-tools:$version" - const val jvmToolPluginDogfooding = "$group:jvm-tool-plugins-all:$dogfoodingVersion" - const val jvmToolPlugins = "$group:jvm-tool-plugins-all:$version" + + // The plain plugin JAR. `jvm-tool-plugins-all` is no longer published + // as of `2.0.0-SNAPSHOT.440`. See https://github.com/SpineEventEngine/tool-base/pull/201 + const val jvmToolPluginDogfooding = "$group:jvm-tool-plugins:$dogfoodingVersion" + const val jvmToolPlugins = "$group:jvm-tool-plugins:$version" const val protobufSetupPlugins = "$group:protobuf-setup-plugins:$version" diff --git a/config b/config index 363fc1da31..ba47b5fb7a 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit 363fc1da3184d001361fa9c327929eb5e05fa673 +Subproject commit ba47b5fb7a92ad1e5399c8714edd2160e0265a82 From d302f1cc6078ef50bd7ce3c603d5ee69751021b5 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 30 Oct 2026 16:32:54 +0000 Subject: [PATCH 11/14] Update local dependency pins Move ToolBase and its dogfooding version to `2.0.0-SNAPSHOT.440`, the first version that publishes `jvm-tool-plugins` and `protobuf-setup-plugins` as plain JARs (SpineEventEngine/tool-base#201). `./config/pull` had reverted `version` to `.428`. Co-Authored-By: Claude Opus 5.5 --- .../src/main/kotlin/io/spine/dependency/local/ToolBase.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt index 7bd22c472a..0a95889ea1 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt @@ -32,8 +32,8 @@ package io.spine.dependency.local ) object ToolBase { const val group = Spine.toolsGroup - const val version = "2.0.0-SNAPSHOT.428" - const val dogfoodingVersion = "2.0.0-SNAPSHOT.428" + const val version = "2.0.0-SNAPSHOT.440" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.440" const val archive = "$group:archive:$version" const val code = "$group:code:$version" From e168253142d36caef54e9ff3f104e6813647fa92 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 30 Oct 2026 16:33:03 +0000 Subject: [PATCH 12/14] Update dependency reports Co-Authored-By: Claude Opus 5.5 --- docs/dependencies/dependencies.md | 34 +++++++++++++++++++++---------- docs/dependencies/pom.xml | 22 ++++++++++---------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index 3d6b80df43..9209055e40 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1817,7 +1817,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2515,7 +2515,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4343,7 +4343,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -6336,7 +6336,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8065,7 +8065,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8155,6 +8155,10 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using * **Project URL:** [https://errorprone.info/error_prone_annotations](https://errorprone.info/error_prone_annotations) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : com.google.gradle. **Name** : osdetector-gradle-plugin. **Version** : 1.7.3. + * **Project URL:** [https://github.com/google/osdetector-gradle-plugin](https://github.com/google/osdetector-gradle-plugin) + * **License:** [Apache License 2.0](http://opensource.org/licenses/Apache-2.0) + 1. **Group** : com.google.guava. **Name** : failureaccess. **Version** : 1.0.3. * **Project URL:** [https://github.com/google/guava/](https://github.com/google/guava/) * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -8172,6 +8176,10 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using * **Project URL:** [https://github.com/google/j2objc/](https://github.com/google/j2objc/) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : com.google.protobuf. **Name** : protobuf-gradle-plugin. **Version** : 0.10.0. + * **Project URL:** [https://github.com/google/protobuf-gradle-plugin](https://github.com/google/protobuf-gradle-plugin) + * **License:** [BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) + 1. **Group** : com.google.protobuf. **Name** : protobuf-java. **Version** : 4.36.2. * **Project URL:** [https://developers.google.com/protocol-buffers/](https://developers.google.com/protocol-buffers/) * **License:** [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) @@ -8399,6 +8407,10 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using * **License:** [https://raw.githubusercontent.com/jaxen-xpath/jaxen/master/LICENSE.txt](https://raw.githubusercontent.com/jaxen-xpath/jaxen/master/LICENSE.txt) * **License:** [BSD License 2.0](https://raw.githubusercontent.com/jaxen-xpath/jaxen/master/LICENSE.txt) +1. **Group** : kr.motd.maven. **Name** : os-maven-plugin. **Version** : 1.7.1. + * **Project URL:** [https://github.com/trustin/os-maven-plugin/](https://github.com/trustin/os-maven-plugin/) + * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + 1. **Group** : net.bytebuddy. **Name** : byte-buddy-agent. **Version** : 1.10.1. * **License:** [http://www.apache.org/licenses/LICENSE-2.0.txt](http://www.apache.org/licenses/LICENSE-2.0.txt) * **License:** [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -9834,7 +9846,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -11685,7 +11697,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -13501,7 +13513,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -14383,7 +14395,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -16207,7 +16219,7 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -18136,6 +18148,6 @@ This report was generated on **Thu Oct 29 19:46:31 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Oct 29 19:46:31 WET 2026** using +This report was generated on **Fri Oct 30 15:46:47 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index 37cd09a73e..475de8f3a2 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -152,37 +152,37 @@ all modules and does not describe the project structure per-subproject. io.spine.tools code - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile io.spine.tools fs - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile io.spine.tools gradle-plugin-api - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile io.spine.tools java-code - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile io.spine.tools jvm-tools - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile io.spine.tools kotlin-code - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile @@ -194,19 +194,19 @@ all modules and does not describe the project structure per-subproject. io.spine.tools plugin-base - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile io.spine.tools proto-code - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile io.spine.tools protobuf-setup-plugins - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile @@ -218,7 +218,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools psi-java - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 compile @@ -308,7 +308,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools plugin-testlib - 2.0.0-SNAPSHOT.430 + 2.0.0-SNAPSHOT.440 test From 852da3fb976e431600c90f413c0c278ff9f93381 Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 30 Oct 2026 16:54:43 +0000 Subject: [PATCH 13/14] Update local dependency pins Move CoreJvm Compiler and its dogfooding version to `2.0.0-SNAPSHOT.101`, which no longer bundles ToolBase classes in `core-jvm-plugins` (SpineEventEngine/core-jvm-compiler#125). The ToolBase classes on the build classpath of projects applying `io.spine.core-jvm` now come from the declared ToolBase `.440` artifacts. Co-Authored-By: Claude Opus 5.5 --- .../main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt index 8fc131eaa8..aa4d53ec75 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -34,12 +34,12 @@ object CoreJvmCompiler { /** * The version used in the build classpath. */ - const val dogfoodingVersion = "2.0.0-SNAPSHOT.099" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.101" /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.099" + const val version = "2.0.0-SNAPSHOT.101" /** * The ID of the Gradle plugin. From 12bda854610ffccbd092ca6d59d0df37b46daf1b Mon Sep 17 00:00:00 2001 From: alexander-yevsyukov Date: Fri, 30 Oct 2026 16:54:44 +0000 Subject: [PATCH 14/14] Update dependency reports Co-Authored-By: Claude Opus 5.5 --- docs/dependencies/dependencies.md | 22 +++++++++++----------- docs/dependencies/pom.xml | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index 9209055e40..e7fe4cd063 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1817,7 +1817,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -2515,7 +2515,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4343,7 +4343,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -6336,7 +6336,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -8065,7 +8065,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -9846,7 +9846,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -11697,7 +11697,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -13513,7 +13513,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -14395,7 +14395,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -16219,7 +16219,7 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -18148,6 +18148,6 @@ This report was generated on **Fri Oct 30 15:46:47 WET 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Oct 30 15:46:47 WET 2026** using +This report was generated on **Fri Oct 30 16:39:00 WET 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/docs/dependencies/pom.xml b/docs/dependencies/pom.xml index 475de8f3a2..f12af6f7a7 100644 --- a/docs/dependencies/pom.xml +++ b/docs/dependencies/pom.xml @@ -415,12 +415,12 @@ all modules and does not describe the project structure per-subproject. io.spine.tools core-jvm-gradle-plugin - 2.0.0-SNAPSHOT.099 + 2.0.0-SNAPSHOT.101 io.spine.tools core-jvm-plugins - 2.0.0-SNAPSHOT.099 + 2.0.0-SNAPSHOT.101 io.spine.tools @@ -435,7 +435,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools time-validation - 2.0.0-SNAPSHOT.251 + 2.0.0-SNAPSHOT.253 io.spine.tools