diff --git a/.github/workflows/build-on-ubuntu.yml b/.github/workflows/build-on-ubuntu.yml
index 27d9302b9d..516f347e14 100644
--- a/.github/workflows/build-on-ubuntu.yml
+++ b/.github/workflows/build-on-ubuntu.yml
@@ -19,9 +19,13 @@ jobs:
- uses: gradle/actions/setup-gradle@v6
- - name: Build project and run tests
+ # `build` does not run Dokka — its tasks are gated to the publishing
+ # graph — so `dokkaGenerate` is appended to surface documentation
+ # warnings on each push, before merge, instead of only in the post-merge
+ # `Publish` job. `failOnWarning` is enabled in the Dokka setup.
+ - name: Build project, run tests, and check documentation
shell: bash
- run: ./gradlew build --stacktrace
+ run: ./gradlew build dokkaGenerate --stacktrace
# See: https://github.com/marketplace/actions/junit-report-action
- name: Publish Test Report
diff --git a/buildSrc/src/main/kotlin/BuildExtensions.kt b/buildSrc/src/main/kotlin/BuildExtensions.kt
index 27c03b4e91..eefdb23e10 100644
--- a/buildSrc/src/main/kotlin/BuildExtensions.kt
+++ b/buildSrc/src/main/kotlin/BuildExtensions.kt
@@ -33,7 +33,6 @@ import io.spine.dependency.build.PluginPublishPlugin
import io.spine.dependency.lib.Protobuf
import io.spine.dependency.local.Compiler
import io.spine.dependency.local.CoreJvmCompiler
-import io.spine.dependency.local.McJava
import io.spine.dependency.local.ProtoTap
import io.spine.dependency.test.Kotest
import io.spine.dependency.test.Kover
@@ -88,12 +87,6 @@ val ScriptHandlerScope.protobuf: Protobuf
val ScriptHandlerScope.coreJvmCompiler: CoreJvmCompiler
get() = CoreJvmCompiler
-/**
- * Shortcut to [McJava] dependency object for using under `buildScript`.
- */
-val ScriptHandlerScope.mcJava: McJava
- get() = McJava
-
/**
* Shortcut to [CoreJvmCompiler] dependency object.
*
@@ -112,10 +105,10 @@ val ScriptHandlerScope.spineCompiler: Compiler
/**
* Shortcut to [Compiler] dependency object.
*
- * This plugin is published at Gradle Plugin Portal.
- * But when used in a pair with [mcJava], it cannot be applied directly to a project.
- * It is so, because [mcJava] uses [spineCompiler] as its dependency.
- * And the buildscript's classpath ends up with both of them.
+ * This plugin is published at Gradle Plugin Portal. But when another plugin that
+ * depends on the Compiler is also on the buildscript's classpath, the Compiler
+ * cannot be applied directly to a project. In such a case, declare it here so that
+ * it is added to the classpath, then apply it by ID.
*/
val PluginDependenciesSpec.spineCompiler: Compiler
get() = Compiler
diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/McJava.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/McJava.kt
deleted file mode 100644
index 6ab0a95656..0000000000
--- a/buildSrc/src/main/kotlin/io/spine/dependency/local/McJava.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2025, TeamDev. All rights reserved.
- *
- * 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.
- */
-
-package io.spine.dependency.local
-
-/**
- * Dependencies on Spine Model Compiler for Java.
- *
- * See [mc-java](https://github.com/SpineEventEngine/mc-java).
- */
-@Suppress(
- "MemberVisibilityCanBePrivate" /* `pluginLib()` is used by subprojects. */,
- "ConstPropertyName",
- "unused"
-)
-object McJava {
- const val group = Spine.toolsGroup
-
- /**
- * The version used to in the build classpath.
- */
- const val dogfoodingVersion = "2.0.0-SNAPSHOT.320"
-
- /**
- * The version to be used for integration tests.
- */
- const val version = "2.0.0-SNAPSHOT.320"
-
- /**
- * The ID of the Gradle plugin.
- */
- const val pluginId = "io.spine.mc-java"
-
- /**
- * The library with the [dogfoodingVersion].
- */
- val pluginLib = pluginLib(dogfoodingVersion)
-
- /**
- * The library with the given [version].
- */
- fun pluginLib(version: String): String = "$group:spine-mc-java-plugins:$version:all"
-
- /** The artifact reference for forcing in configurations. */
- const val pluginsArtifact: String = "$group:spine-mc-java-plugins:$version"
-
- /**
- * The `mc-java-base` artifact with the [version].
- */
- val base = base(version)
-
- /**
- * The `mc-java-base` artifact with the given [version].
- */
- fun base(version: String): String = "$group:spine-mc-java-base:$version"
-}
diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoData.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoData.kt
deleted file mode 100644
index c4f06c8fd2..0000000000
--- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoData.kt
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2025, TeamDev. All rights reserved.
- *
- * 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.
- */
-
-package io.spine.dependency.local
-
-/**
- * Dependencies on ProtoData modules.
- *
- * To use a locally published ProtoData version instead of the version from a public plugin
- * registry, set the `PROTODATA_VERSION` and/or the `PROTODATA_DF_VERSION` environment variables
- * and stop the Gradle daemons so that Gradle observes the env change:
- * ```
- * export PROTODATA_VERSION=0.43.0-local
- * export PROTODATA_DF_VERSION=0.41.0
- *
- * ./gradle --stop
- * ./gradle build # Conduct the intended checks.
- * ```
- *
- * Then, to reset the console to run the usual versions again, remove the values of
- * the environment variables and stop the daemon:
- * ```
- * export PROTODATA_VERSION=""
- * export PROTODATA_DF_VERSION=""
- *
- * ./gradle --stop
- * ```
- *
- * See [`SpineEventEngine/ProtoData`](https://github.com/SpineEventEngine/ProtoData/).
- */
-@Suppress(
- "unused" /* Some subprojects do not use ProtoData directly. */,
- "ConstPropertyName" /* We use custom convention for artifact properties. */,
- "MemberVisibilityCanBePrivate" /* The properties are used directly by other subprojects. */,
-)
-object ProtoData {
- const val pluginGroup = Spine.group
- const val group = "io.spine.protodata"
- const val pluginId = "io.spine.protodata"
-
- /**
- * Identifies ProtoData as a `classpath` dependency under `buildScript` block.
- *
- * The dependency is obtained from https://plugins.gradle.org/m2/.
- */
- const val module = "io.spine:protodata"
-
- /**
- * The version of ProtoData dependencies.
- */
- val version: String
- private const val fallbackVersion = "0.96.4"
-
- /**
- * The distinct version of ProtoData used by other build tools.
- *
- * When ProtoData is used both for building the project and as a part of the Project's
- * transitional dependencies, this is the version used to build the project itself.
- */
- val dogfoodingVersion: String
- private const val fallbackDfVersion = "0.96.4"
-
- /**
- * The artifact for the ProtoData Gradle plugin.
- */
- val pluginLib: String
-
- /**
- * The artifact to be used during experiments when publishing locally.
- *
- * @see ProtoData
- */
- private fun pluginLib(version: String): String =
- "$group:gradle-plugin:$version"
-
- fun api(version: String): String =
- "$group:protodata-api:$version"
-
- val api
- get() = api(version)
-
- val backend
- get() = "$group:protodata-backend:$version"
-
- val params
- get() = "$group:protodata-params:$version"
-
- val protocPlugin
- get() = "$group:protodata-protoc:$version"
-
- val gradleApi
- get() = "$group:protodata-gradle-api:$version"
-
- val cliApi
- get() = "$group:protodata-cli-api:$version"
-
- val javaModule = "$group:protodata-java"
-
- fun java(version: String): String =
- "$javaModule:$version"
-
- val java
- get() = java(version)
-
- val fatCli
- get() = "$group:protodata-fat-cli:$version"
-
- val testlib
- get() = "$group:protodata-testlib:$version"
-
- /**
- * An env variable storing a custom [version].
- */
- private const val VERSION_ENV = "PROTODATA_VERSION"
-
- /**
- * An env variable storing a custom [dogfoodingVersion].
- */
- private const val DF_VERSION_ENV = "PROTODATA_DF_VERSION"
-
- /**
- * Sets up the versions and artifacts for the build to use.
- *
- * If either [VERSION_ENV] or [DF_VERSION_ENV] is set, those versions are used instead of
- * the hardcoded ones. Also, in this mode, the [pluginLib] coordinates are changed so that
- * it points at a locally published artifact. Otherwise, it points at an artifact that would be
- * published to a public plugin registry.
- */
- init {
- val experimentVersion = System.getenv(VERSION_ENV)
- val experimentDfVersion = System.getenv(DF_VERSION_ENV)
- if (experimentVersion?.isNotBlank() == true || experimentDfVersion?.isNotBlank() == true) {
- version = experimentVersion ?: fallbackVersion
- dogfoodingVersion = experimentDfVersion ?: fallbackDfVersion
-
- pluginLib = pluginLib(version)
- println("""
-
- ❗ Running an experiment with ProtoData. ❗
- -----------------------------------------
- Regular version = v$version
- Dogfooding version = v$dogfoodingVersion
-
- ProtoData Gradle plugin can now be loaded from Maven Local.
-
- To reset the versions, erase the `$$VERSION_ENV` and `$$DF_VERSION_ENV` environment variables.
-
- """.trimIndent())
- } else {
- version = fallbackVersion
- dogfoodingVersion = fallbackDfVersion
- pluginLib = "$pluginGroup:protodata:$version"
- }
- }
-}
diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt
index 21a6031052..0110a32f75 100644
--- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt
+++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ProtoTap.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2025, TeamDev. All rights reserved.
+ * Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ package io.spine.dependency.local
)
object ProtoTap {
const val group = Spine.toolsGroup
- const val version = "0.14.0"
+ const val version = "0.15.0"
const val gradlePluginId = "io.spine.prototap"
const val api = "$group:prototap-api:$version"
const val gradlePlugin = "$group:prototap-gradle-plugin:$version"
diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt
index 6c63a31248..c25868fc11 100644
--- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt
+++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/GitHubPackages.kt
@@ -82,8 +82,8 @@ private fun Project.readGitHubToken(): String {
}
/**
- * Read the personal access token for the `developers@spine.io` account that
- * has only the permission to read public GitHub packages.
+ * Reads the personal access token for the `developers@spine.io` account.
+ * The token grants only read access to public GitHub packages.
*
* The token is extracted from the archive called `aus.weis` stored under `buildSrc`.
* The archive has such an unusual name to avoid scanning for tokens placed in repositories
diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt
index 79d00c6299..db2bf761ae 100644
--- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt
+++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/DependencyWriter.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2025, TeamDev. All rights reserved.
+ * Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,7 +54,9 @@ import org.gradle.kotlin.dsl.withGroovyBuilder
* ```
*
* When there are several versions of the same dependency, only the one with
- * the newest version is retained.
+ * the newest version is retained. If the retained version is used in several
+ * configurations, the highest-ranking Maven scope is reported, e.g. `compile`
+ * wins over `test`.
*
* @see PomGenerator
*/
@@ -65,7 +67,7 @@ private constructor(
internal companion object {
/**
- * Creates the `ProjectDependenciesAsXml` for the passed [project].
+ * Creates the `DependencyWriter` for the passed [project].
*/
fun of(project: Project): DependencyWriter {
return DependencyWriter(project.dependencies())
@@ -75,7 +77,7 @@ private constructor(
/**
* Writes the dependencies in their `pom.xml` format to the passed [out] writer.
*
- *
Used writer will not be closed.
+ * The used writer will not be closed.
*/
fun writeXmlTo(out: Writer) {
val xml = MarkupBuilder(out)
@@ -86,7 +88,12 @@ private constructor(
"dependency" {
"groupId" { xml.text(dependency.group) }
"artifactId" { xml.text(dependency.name) }
- "version" { xml.text(dependency.version) }
+ // A BOM-managed dependency carries no explicit version.
+ // Omit the element rather than emit `null`,
+ // since `null` is not a valid Maven version.
+ dependency.version?.let { version ->
+ "version" { xml.text(version) }
+ }
if (scopedDep.hasDefinedScope()) {
"scope" { xml.text(scopedDep.scopeName()) }
}
@@ -170,17 +177,30 @@ private fun Dependency.isExternal(): Boolean {
* But for our `pom.xml`, which has clearly representative character, a single version
* of a dependency is quite enough.
*
+ * Versions are compared by [VersionComparator] rather than as plain text, so `10.0.0`
+ * is recognized as newer than `9.2.0`, and `2.0.0-SNAPSHOT.100` — as newer
+ * than `2.0.0-SNAPSHOT.99`.
+ *
+ * When the newest version comes from several configurations, the occurrence with
+ * the highest-ranking Maven scope (as defined by [ScopedDependency.dependencyPriority])
+ * is retained. For example, a dependency declared via `api` in one module and via
+ * `testImplementation` in another is reported with the `compile` scope, so a production
+ * dependency is not misrepresented as a test-scoped one. Likewise, an artifact coming
+ * from `compileOnly` or `annotationProcessor` in one module and from a test
+ * configuration in another is reported as `provided`.
+ *
* The rejected duplicates are logged.
*/
private fun Project.deduplicate(dependencies: Set): List {
- val groups = dependencies.distinctBy { it.gav }
- .groupBy { it.run { "$group:$name" } }
+ val groups = dependencies.groupBy { it.run { "$group:$name" } }
- logDuplicates(groups)
+ logDuplicates(groups.mapValues { (_, deps) -> deps.distinctBy { it.gav } })
- val filtered = groups.map { group ->
- group.value.maxByOrNull { dep -> dep.version ?: "" }
- }.filterNotNull()
+ val filtered = groups.values.map { sameArtifact ->
+ val newest = sameArtifact.maxWith(compareBy(VersionComparator) { it.version ?: "" })
+ sameArtifact.filter { it.version == newest.version }
+ .minBy { it.scoped.dependencyPriority() }
+ }
return filtered
}
diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ScopedDependency.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ScopedDependency.kt
index 7c67a32ca4..c969ce5008 100644
--- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ScopedDependency.kt
+++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ScopedDependency.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2025, TeamDev. All rights reserved.
+ * Copyright 2026, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ package io.spine.gradle.report.pom
import io.spine.gradle.report.pom.DependencyScope.compile
import io.spine.gradle.report.pom.DependencyScope.provided
import io.spine.gradle.report.pom.DependencyScope.runtime
+import io.spine.gradle.report.pom.DependencyScope.system
import io.spine.gradle.report.pom.DependencyScope.test
import io.spine.gradle.report.pom.DependencyScope.undefined
import org.gradle.api.artifacts.Configuration
@@ -106,17 +107,18 @@ private constructor(
configurationName.startsWith("test", ignoreCase = true)
/**
- * Performs comparison of {@code DependencyWithScope} instances according to these rules:
+ * Performs comparison of `ScopedDependency` instances according to these rules:
*
- * * Compares the scope of the dependency first. Dependency with lower scope priority
- * number goes first.
+ * * Compares the scope of the dependency first. Dependency with a lower scope priority
+ * number goes first.
*
- * * For dependencies with same scope, does the lexicographical group name comparison.
+ * * For dependencies with the **same scope** does the lexicographical group
+ * name comparison.
*
- * * For dependencies within the same group, does the lexicographical artifact
+ * * For dependencies within the **same group**, does the lexicographical artifact
* name comparison.
*
- * * For dependencies with the same artifact name, does the lexicographical artifact
+ * * For dependencies with the **same artifact name**, does the lexicographical artifact
* version comparison.
*/
private val COMPARATOR: Comparator =
@@ -138,7 +140,7 @@ private constructor(
return dependency
}
- /** Obtains the scope name of this dependency .*/
+ /** Obtains the scope name of this dependency. */
fun scopeName(): String {
return scope.name
}
@@ -147,14 +149,24 @@ private constructor(
* Obtains the layout priority of a scope.
*
* Layout priority determines what scopes come first in the generated `pom.xml` file.
- * Dependencies with a lower priority number go on top.
+ * Dependencies with a lower priority number go on top, following the conventional
+ * Maven scope order: `compile`, `provided`, `runtime`, `test`, and `system`.
+ * Dependencies with an undefined scope go last.
+ *
+ * The same ordering also drives the scope selection when the same dependency
+ * comes from several configurations: the occurrence with the lowest priority
+ * number is reported. So, a scope required by production code wins over `test`,
+ * and a known scope wins over an undefined one.
*/
+ @Suppress("MagicNumber") // Reason: the values encode the relative scope order.
internal fun dependencyPriority(): Int {
return when (scope) {
compile -> 0
- runtime -> 1
- test -> 2
- else -> 3
+ provided -> 1
+ runtime -> 2
+ test -> 3
+ system -> 4
+ undefined -> 5
}
}
diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/VersionComparator.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/VersionComparator.kt
new file mode 100644
index 0000000000..c6984bb65c
--- /dev/null
+++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/VersionComparator.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2026, TeamDev. All rights reserved.
+ *
+ * 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.
+ */
+
+package io.spine.gradle.report.pom
+
+/**
+ * Compares dependency version strings by their meaning rather than lexicographically.
+ *
+ * Numeric segments are ordered as numbers, so `10.0.0` is newer than `9.2.0`, and
+ * `2.0.0-SNAPSHOT.100` is newer than `2.0.0-SNAPSHOT.99`. A plain `String` comparison
+ * would order both pairs the other way around.
+ *
+ * The rules follow Semantic Versioning where it applies:
+ *
+ * 1. A version consists of a release part and an optional qualifier, separated by
+ * the first `-`: for `2.0.0-SNAPSHOT.100` these are `2.0.0` and `SNAPSHOT.100`.
+ * 2. Both parts are compared segment by segment, as split by `.`, and also by `-`
+ * within a qualifier. Two numeric segments are compared as numbers, two textual
+ * ones as case-insensitive text, and a numeric segment is older than a textual one.
+ * 3. When one version runs out of segments, it is the older one: `1.0.1` is newer
+ * than `1.0`, and `1.0.0-RC.1` is newer than `1.0.0-RC`.
+ * 4. When the release parts are equal, a version without a qualifier is newer than
+ * a version with one: `2.0.0` is newer than `2.0.0-SNAPSHOT.100`.
+ *
+ * Unlike full Maven semantics, qualifiers carry no special meaning: `RC`, `SNAPSHOT`,
+ * and the like are ordered as plain text. This keeps the comparison simple and
+ * predictable for the report, where only the relative recency of the versions
+ * of the same artifact matters.
+ */
+internal object VersionComparator : Comparator {
+
+ override fun compare(left: String, right: String): Int {
+ val (leftRelease, leftQualifier) = left.parse()
+ val (rightRelease, rightQualifier) = right.parse()
+ val byRelease = compareSegments(leftRelease, rightRelease)
+ if (byRelease != 0) {
+ return byRelease
+ }
+ return when {
+ leftQualifier == null && rightQualifier == null -> 0
+ leftQualifier == null -> 1
+ rightQualifier == null -> -1
+ else -> compareSegments(leftQualifier, rightQualifier)
+ }
+ }
+
+ /**
+ * Splits this version into the segments of its release part and the segments
+ * of its qualifier, the latter being `null` when the version has no qualifier.
+ */
+ private fun String.parse(): Pair, List?> {
+ val release = substringBefore('-')
+ val qualifier = if ('-' in this) substringAfter('-') else null
+ return release.split('.') to qualifier?.split('.', '-')
+ }
+
+ private fun compareSegments(left: List, right: List): Int {
+ for (index in 0 until maxOf(left.size, right.size)) {
+ val bySegment = compareSegment(
+ left.getOrElse(index) { "" },
+ right.getOrElse(index) { "" }
+ )
+ if (bySegment != 0) {
+ return bySegment
+ }
+ }
+ return 0
+ }
+
+ /**
+ * Compares single segments, ordering an absent (empty) segment below any present
+ * one, a numeric segment below a textual one, numbers by their value, and text
+ * case-insensitively.
+ *
+ * Keeping the empty, numeric, and textual segments in distinct buckets makes
+ * the order transitive: comparing a numeric pair as numbers, but a mixed pair
+ * as text, would order `2` < `10` < `1a` < `2`.
+ */
+ private fun compareSegment(left: String, right: String): Int {
+ if (left.isEmpty() || right.isEmpty()) {
+ return left.length.compareTo(right.length)
+ }
+ val leftNumber = left.toLongOrNull()
+ val rightNumber = right.toLongOrNull()
+ return when {
+ leftNumber != null && rightNumber != null -> leftNumber.compareTo(rightNumber)
+ leftNumber != null -> -1
+ rightNumber != null -> 1
+ else -> left.compareTo(right, ignoreCase = true)
+ }
+ }
+}
diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt
new file mode 100644
index 0000000000..3a9da7294b
--- /dev/null
+++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2026, TeamDev. All rights reserved.
+ *
+ * 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.
+ */
+
+package io.spine.gradle.report.pom
+
+import io.kotest.matchers.ints.shouldBeGreaterThan
+import io.kotest.matchers.ints.shouldBeLessThan
+import io.kotest.matchers.shouldBe
+import io.kotest.matchers.string.shouldContain
+import io.kotest.matchers.string.shouldNotContain
+import java.io.StringWriter
+import org.gradle.api.Project
+import org.gradle.testfixtures.ProjectBuilder
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Nested
+import org.junit.jupiter.api.Test
+
+@DisplayName("`DependencyWriter` should")
+internal class DependencyWriterSpec {
+
+ private val rootProject: Project = ProjectBuilder.builder().withName("root").build()
+
+ /**
+ * Creates a subproject of the [rootProject] with the given name.
+ *
+ * The names of the subprojects in the tests below are chosen so that
+ * a module using a dependency in a lower-ranked scope — as defined by
+ * [ScopedDependency.dependencyPriority] — sorts first, and is thus
+ * encountered first when the dependencies are collected. This way,
+ * the tests prove that the merged scope does not depend on the order
+ * in which project modules are traversed.
+ */
+ private fun subproject(name: String): Project =
+ ProjectBuilder.builder().withParent(rootProject).withName(name).build()
+
+ /**
+ * Declares a dependency with the given [notation] in the named [configuration],
+ * creating it if it does not exist.
+ */
+ private fun Project.declare(configuration: String, notation: String) {
+ configurations.maybeCreate(configuration)
+ dependencies.add(configuration, notation)
+ }
+
+ @Nested inner class
+ `merge an artifact duplicated across modules` {
+
+ @Test
+ fun `preferring the 'compile' scope over the 'test' one`() {
+ subproject("a-tests").declare("testImplementation", SPINE_BASE)
+ subproject("b-lib").declare("api", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.scopeName() shouldBe DependencyScope.compile.name
+ }
+
+ @Test
+ fun `preferring the 'runtime' scope over the 'test' one`() {
+ subproject("a-tests").declare("testImplementation", SPINE_BASE)
+ subproject("b-lib").declare("runtimeOnly", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.scopeName() shouldBe DependencyScope.runtime.name
+ }
+
+ @Test
+ fun `preferring the 'compile' scope over the 'runtime' one`() {
+ subproject("a-run").declare("runtimeOnly", SPINE_BASE)
+ subproject("b-lib").declare("implementation", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.scopeName() shouldBe DependencyScope.compile.name
+ }
+
+ @Test
+ fun `preferring the 'provided' scope over the 'test' one`() {
+ subproject("a-tests").declare("testImplementation", SPINE_BASE)
+ subproject("b-lib").declare("compileOnly", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.scopeName() shouldBe DependencyScope.provided.name
+ }
+
+ @Test
+ fun `reporting 'annotationProcessor' and 'testAnnotationProcessor' usages as 'provided'`() {
+ subproject("a-tests").declare("testAnnotationProcessor", SPINE_BASE)
+ subproject("b-codegen").declare("annotationProcessor", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.scopeName() shouldBe DependencyScope.provided.name
+ }
+
+ @Test
+ fun `preferring the 'compile' scope over the 'provided' one`() {
+ subproject("a-tools").declare("compileOnly", SPINE_BASE)
+ subproject("b-lib").declare("implementation", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.scopeName() shouldBe DependencyScope.compile.name
+ }
+
+ @Test
+ fun `preferring the 'provided' scope over the 'runtime' one`() {
+ subproject("a-run").declare("runtimeOnly", SPINE_BASE)
+ subproject("b-tools").declare("compileOnly", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.scopeName() shouldBe DependencyScope.provided.name
+ }
+
+ @Test
+ fun `retaining the newest version with the widest of its scopes`() {
+ subproject("a-tests").declare("testImplementation", SPINE_BASE_NEWER)
+ subproject("b-lib").declare("api", SPINE_BASE_NEWER)
+ subproject("c-old").declare("api", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.dependency().version shouldBe "2.0.1"
+ dependency.scopeName() shouldBe DependencyScope.compile.name
+ }
+
+ @Test
+ fun `comparing versions semantically rather than as text`() {
+ subproject("a-lib").declare("api", "io.spine:spine-base:9.2.0")
+ subproject("b-lib").declare("api", "io.spine:spine-base:10.0.0")
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.dependency().version shouldBe "10.0.0"
+ }
+
+ @Test
+ fun `ordering pre-release increments numerically`() {
+ subproject("a-old").declare("api", "io.spine:spine-base:2.0.0-SNAPSHOT.99")
+ subproject("b-new").declare("api", "io.spine:spine-base:2.0.0-SNAPSHOT.100")
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.dependency().version shouldBe "2.0.0-SNAPSHOT.100"
+ }
+
+ @Test
+ fun `preferring a release over its pre-release`() {
+ subproject("a-snapshot").declare("api", "io.spine:spine-base:2.0.0-SNAPSHOT.100")
+ subproject("b-release").declare("api", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.dependency().version shouldBe "2.0.0"
+ }
+
+ /**
+ * The `api` usage of the older `9.2.0` must affect neither the version
+ * nor the scope: both come from the usages of the newest `10.0.0`,
+ * which would lose to `9.2.0` in a plain text comparison.
+ */
+ @Test
+ fun `taking the widest scope from the usages of the numerically newest version`() {
+ subproject("a-lib").declare("api", "io.spine:spine-base:9.2.0")
+ subproject("b-tests").declare("testImplementation", "io.spine:spine-base:10.0.0")
+ subproject("c-run").declare("runtimeOnly", "io.spine:spine-base:10.0.0")
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.dependency().version shouldBe "10.0.0"
+ dependency.scopeName() shouldBe DependencyScope.runtime.name
+ }
+
+ /**
+ * When the newest version of an artifact occurs only in test configurations,
+ * the `test` scope is reported even if an older version is a production
+ * dependency: the report describes the retained version as it is used.
+ */
+ @Test
+ fun `taking the scope only from the usages of the newest version`() {
+ subproject("a-tests").declare("testImplementation", SPINE_BASE_NEWER)
+ subproject("b-lib").declare("api", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.dependency().version shouldBe "2.0.1"
+ dependency.scopeName() shouldBe DependencyScope.test.name
+ }
+
+ @Test
+ fun `keeping the 'test' scope for an artifact used only in tests`() {
+ subproject("a-tests").declare("testImplementation", SPINE_BASE)
+ subproject("b-tests").declare("testRuntimeOnly", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.scopeName() shouldBe DependencyScope.test.name
+ }
+
+ @Test
+ fun `preferring a known scope over that of an unknown configuration`() {
+ subproject("a-tools").declare("protoData", SPINE_BASE)
+ subproject("b-tests").declare("testImplementation", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.hasDefinedScope() shouldBe true
+ dependency.scopeName() shouldBe DependencyScope.test.name
+ }
+
+ @Test
+ fun `preferring the 'provided' scope over that of an unknown configuration`() {
+ subproject("a-tools").declare("protoData", SPINE_BASE)
+ subproject("b-lib").declare("compileOnly", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.hasDefinedScope() shouldBe true
+ dependency.scopeName() shouldBe DependencyScope.provided.name
+ }
+ }
+
+ @Test
+ fun `omit the scope of a dependency coming only from an unknown configuration`() {
+ subproject("lib").declare("protoData", SPINE_BASE)
+
+ val dependency = rootProject.dependencies().single()
+
+ dependency.hasDefinedScope() shouldBe false
+ }
+
+ @Test
+ fun `omit the version of a dependency that declares none`() {
+ subproject("a-bom").declare("api", "io.grpc:grpc-stub")
+ subproject("b-lib").declare("api", SPINE_BASE)
+
+ val out = StringWriter()
+ DependencyWriter.of(rootProject).writeXmlTo(out)
+ val xml = out.toString()
+
+ xml shouldContain "grpc-stub"
+ xml shouldNotContain "null"
+ xml shouldContain "2.0.0"
+ }
+
+ @Test
+ fun `write a production dependency as 'compile' even when it is also used in tests`() {
+ subproject("a-tests").declare("testImplementation", SPINE_BASE)
+ subproject("b-lib").declare("api", SPINE_BASE)
+
+ val out = StringWriter()
+ DependencyWriter.of(rootProject).writeXmlTo(out)
+ val xml = out.toString()
+
+ xml shouldContain "spine-base"
+ xml shouldContain "compile"
+ xml shouldNotContain "test"
+ }
+
+ @Test
+ fun `lay out dependencies in the conventional Maven scope order`() {
+ subproject("a-tests").declare("testImplementation", "io.spine:spine-testlib:2.0.0")
+ subproject("b-run").declare("runtimeOnly", "io.spine:spine-logging:2.0.0")
+ subproject("c-tools").declare("annotationProcessor", "io.spine:spine-validate:2.0.0")
+ subproject("d-lib").declare("api", SPINE_BASE)
+
+ val out = StringWriter()
+ DependencyWriter.of(rootProject).writeXmlTo(out)
+ val xml = out.toString()
+
+ val compileAt = xml.indexOf("compile")
+ val providedAt = xml.indexOf("provided")
+ val runtimeAt = xml.indexOf("runtime")
+ val testAt = xml.indexOf("test")
+
+ compileAt shouldBeGreaterThan -1
+ compileAt shouldBeLessThan providedAt
+ providedAt shouldBeLessThan runtimeAt
+ runtimeAt shouldBeLessThan testAt
+ }
+
+ private companion object {
+ const val SPINE_BASE = "io.spine:spine-base:2.0.0"
+ const val SPINE_BASE_NEWER = "io.spine:spine-base:2.0.1"
+ }
+}
diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/VersionComparatorSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/VersionComparatorSpec.kt
new file mode 100644
index 0000000000..54b6439505
--- /dev/null
+++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/VersionComparatorSpec.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2026, TeamDev. All rights reserved.
+ *
+ * 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.
+ */
+
+package io.spine.gradle.report.pom
+
+import io.kotest.matchers.ints.shouldBeGreaterThan
+import io.kotest.matchers.ints.shouldBeLessThan
+import io.kotest.matchers.shouldBe
+import org.junit.jupiter.api.DisplayName
+import org.junit.jupiter.api.Test
+
+@DisplayName("`VersionComparator` should")
+internal class VersionComparatorSpec {
+
+ /**
+ * Asserts that [newer] compares above [older], checking both directions.
+ */
+ private fun assertNewer(newer: String, older: String) {
+ VersionComparator.compare(newer, older) shouldBeGreaterThan 0
+ VersionComparator.compare(older, newer) shouldBeLessThan 0
+ }
+
+ @Test
+ fun `compare numeric segments as numbers`() {
+ assertNewer("10.0.0", "9.2.0")
+ assertNewer("2.10.0", "2.9.1")
+ assertNewer("1.0.10", "1.0.9")
+ }
+
+ @Test
+ fun `compare numeric qualifier segments as numbers`() {
+ assertNewer("2.0.0-SNAPSHOT.100", "2.0.0-SNAPSHOT.99")
+ assertNewer("2.0.0-SNAPSHOT.100", "2.0.0-SNAPSHOT.070")
+ }
+
+ @Test
+ fun `treat a release as newer than its pre-release`() {
+ assertNewer("2.0.0", "2.0.0-SNAPSHOT.100")
+ assertNewer("1.0.0", "1.0.0-RC.2")
+ }
+
+ @Test
+ fun `treat a longer version as newer when the common segments are equal`() {
+ assertNewer("1.0.1", "1.0")
+ assertNewer("1.0.0-RC.1", "1.0.0-RC")
+ }
+
+ @Test
+ fun `ignore the case of textual segments`() {
+ assertNewer("1.0.0-snapshot.10", "1.0.0-SNAPSHOT.2")
+ VersionComparator.compare("1.0.0-RC", "1.0.0-rc") shouldBe 0
+ }
+
+ @Test
+ fun `order a numeric segment before a textual one`() {
+ assertNewer("1.0.0-alpha", "1.0.0-1")
+ }
+
+ @Test
+ fun `treat equal versions as equal`() {
+ VersionComparator.compare("2.0.0-SNAPSHOT.070", "2.0.0-SNAPSHOT.070") shouldBe 0
+ VersionComparator.compare("31.1-jre", "31.1-jre") shouldBe 0
+ }
+}
diff --git a/config b/config
index 5a13d5b29d..aea90ae9cf 160000
--- a/config
+++ b/config
@@ -1 +1 @@
-Subproject commit 5a13d5b29d04ed414e2bc1ef3a3409a51f10846a
+Subproject commit aea90ae9cf4c263d0cf5b1d6817c905923cb025e
diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md
index 061e0b13af..86ed5ce085 100644
--- a/docs/dependencies/dependencies.md
+++ b/docs/dependencies/dependencies.md
@@ -1,6 +1,6 @@
-# Dependencies of `io.spine:spine-annotations:2.0.0-SNAPSHOT.412`
+# Dependencies of `io.spine:spine-annotations:2.0.0-SNAPSHOT.413`
## Runtime
1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0.
@@ -760,14 +760,14 @@
The dependencies distributed under several licenses, are used according their commercial-use-friendly license.
-This report was generated on **Mon Jun 15 20:41:55 WEST 2026** using
+This report was generated on **Tue Jun 16 17:11:42 WEST 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:spine-base:2.0.0-SNAPSHOT.412`
+# Dependencies of `io.spine:spine-base:2.0.0-SNAPSHOT.413`
## Runtime
1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2.
@@ -1604,14 +1604,14 @@ This report was generated on **Mon Jun 15 20:41:55 WEST 2026** using
The dependencies distributed under several licenses, are used according their commercial-use-friendly license.
-This report was generated on **Mon Jun 15 20:41:55 WEST 2026** using
+This report was generated on **Tue Jun 16 17:11:42 WEST 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:spine-environment:2.0.0-SNAPSHOT.412`
+# Dependencies of `io.spine:spine-environment:2.0.0-SNAPSHOT.413`
## Runtime
1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2.
@@ -2430,14 +2430,14 @@ This report was generated on **Mon Jun 15 20:41:55 WEST 2026** using
The dependencies distributed under several licenses, are used according their commercial-use-friendly license.
-This report was generated on **Mon Jun 15 20:41:55 WEST 2026** using
+This report was generated on **Tue Jun 16 17:11:42 WEST 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:spine-format:2.0.0-SNAPSHOT.412`
+# Dependencies of `io.spine:spine-format:2.0.0-SNAPSHOT.413`
## Runtime
1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.0.
@@ -3336,6 +3336,6 @@ This report was generated on **Mon Jun 15 20:41:55 WEST 2026** using
The dependencies distributed under several licenses, are used according their commercial-use-friendly license.
-This report was generated on **Mon Jun 15 20:41:55 WEST 2026** using
+This report was generated on **Tue Jun 16 17:11:42 WEST 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 0fb5ff07b9..cbff2813ac 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
base-libraries
-2.0.0-SNAPSHOT.412
+2.0.0-SNAPSHOT.413
2015
@@ -32,31 +32,26 @@ all modules and does not describe the project structure per-subproject.
com.fasterxml.jackson.core
jackson-databind
- null
compile
com.fasterxml.jackson.dataformat
jackson-dataformat-yaml
- null
compile
com.fasterxml.jackson.datatype
jackson-datatype-guava
- null
compile
com.fasterxml.jackson.datatype
jackson-datatype-jdk8
- null
compile
com.fasterxml.jackson.datatype
jackson-datatype-jsr310
- null
compile
@@ -125,10 +120,33 @@ all modules and does not describe the project structure per-subproject.
1.0.0
compile
+
+ com.google.auto.service
+ auto-service-annotations
+ 1.1.1
+ provided
+
+
+ com.google.errorprone
+ error_prone_annotations
+ 2.36.0
+ provided
+
+
+ com.google.errorprone
+ error_prone_type_annotations
+ 2.36.0
+ provided
+
+
+ org.checkerframework
+ checker-qual
+ 4.2.0
+ provided
+
com.fasterxml.jackson.module
jackson-module-kotlin
- null
runtime
@@ -191,34 +209,16 @@ all modules and does not describe the project structure per-subproject.
6.1.0
test
-
- com.google.auto.service
- auto-service-annotations
- 1.1.1
- provided
-
com.google.devtools.ksp
symbol-processing-api
2.3.9
-
- com.google.errorprone
- error_prone_annotations
- 2.36.0
- provided
-
com.google.errorprone
error_prone_core
2.36.0
-
- com.google.errorprone
- error_prone_type_annotations
- 2.36.0
- provided
-
com.google.protobuf
protoc
@@ -254,12 +254,6 @@ all modules and does not describe the project structure per-subproject.
pmd-java
7.25.0
-
- org.checkerframework
- checker-qual
- 4.2.0
- provided
-
org.jacoco
org.jacoco.agent
diff --git a/version.gradle.kts b/version.gradle.kts
index de40c109da..edbaca1e74 100644
--- a/version.gradle.kts
+++ b/version.gradle.kts
@@ -24,4 +24,4 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-val versionToPublish: String by extra("2.0.0-SNAPSHOT.412")
+val versionToPublish: String by extra("2.0.0-SNAPSHOT.413")