diff --git a/.claude/settings.json b/.claude/settings.json index 84a0e53d..357650cf 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/claude-code-settings.json", "permissions": { "allow": [ + "Edit(version.gradle.kts)", "Bash(./gradlew:*)", "Bash(./config/gradlew:*)", "Bash(git status:*)", diff --git a/.github/workflows/build-on-ubuntu.yml b/.github/workflows/build-on-ubuntu.yml index 01f6fd71..b07bf0fb 100644 --- a/.github/workflows/build-on-ubuntu.yml +++ b/.github/workflows/build-on-ubuntu.yml @@ -87,7 +87,7 @@ jobs: # there anyway). - name: Upload code coverage report if: steps.codecov.outputs.available == 'true' || github.event_name == 'push' - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true diff --git a/.github/workflows/increment-guard.yml b/.github/workflows/increment-guard.yml index f20b4bed..9a6333f0 100644 --- a/.github/workflows/increment-guard.yml +++ b/.github/workflows/increment-guard.yml @@ -1,5 +1,9 @@ -# Ensures that the current lib version is not yet published by executing the Gradle -# `checkVersionIncrement` task. +# 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). # # 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 @@ -15,19 +19,45 @@ name: Version Guard 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: + # * `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. + types: [opened, synchronize, reopened, ready_for_review, edited] jobs: check: name: Check version increment runs-on: ubuntu-latest - # Default and release-line branches, e.g. `master`, `main`, `2.x-jdk8-master`. - if: endsWith(github.base_ref, 'master') || endsWith(github.base_ref, 'main') + # Default and release-line branches, e.g. `master`, `main`, `2.x-jdk8-master`. For an + # `edited` event, run only when the base actually changed (a retarget carries + # `changes.base.ref.from`); title/body edits carry no `changes.base` and are skipped, so + # the guard is not rebuilt needlessly. + if: >- + (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 + # branch protection requires. + permissions: + contents: read + statuses: write steps: - uses: actions/checkout@v6 with: submodules: 'true' + # `checkVersionIncrement` reads `origin/:version.gradle.kts`. The pull request + # checkout does not include the base branch, so fetch its tip into the expected ref. + - name: Fetch the base branch + shell: bash + run: | + git fetch --no-tags --depth=1 \ + origin "+refs/heads/${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF}" + - uses: actions/setup-java@v5 with: java-version: 17 @@ -35,6 +65,36 @@ jobs: - uses: gradle/actions/setup-gradle@v6 - - name: Check version is not yet published + - name: Check version increment + id: guard shell: bash + # `VERSION_GUARD` enables the strict base-branch comparison in `checkVersionIncrement`. + # Only this workflow fetches the base ref (the step above), so the comparison is gated + # to it: other CI builds pull the task in via `publishToMavenLocal` on a shallow + # checkout and must not attempt to read `origin/`. + env: + VERSION_GUARD: "true" run: ./gradlew checkVersionIncrement --stacktrace + + # Publish the verdict as the `Version Guard` 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. + # + # Skipped for fork PRs: `GITHUB_TOKEN` is read-only for them, so the status cannot be + # 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 + if: always() && github.event.pull_request.head.repo.fork == false + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + state=failure + if [ "${{ steps.guard.outcome }}" = "success" ]; then + state=success + fi + gh api -X POST "repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \ + -f state="${state}" \ + -f context="Version Guard" \ + -f description="Version increment check" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index df8f6cd0..27c11c0f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -64,3 +64,18 @@ jobs: REPO_SLUG: ${{ github.repository }} # e.g. SpineEventEngine/core-jvm GOOGLE_APPLICATION_CREDENTIALS: ./maven-publisher.json NPM_TOKEN: ${{ secrets.NPM_SECRET }} + + # A failed publication on `master` is most often a version collision: a stale + # duplicate bump merged before `revalidate-versions.yml` could turn it red (the + # narrow auto-merge race). The artifact is safe — the registry rejects the + # overwrite — but the fix needs a human/agent, so make the failure loud and + # actionable instead of a quiet red run. + - name: Report a failed publication + if: failure() + shell: bash + run: | + echo "::error title=Publish failed::Publishing to Maven failed on the base branch. If this is a version collision, the version is already published (immutable). Bump 'version.gradle.kts' on the base branch (e.g. via a small PR) and re-run this workflow." + echo "Publish failed. If the cause is a version collision:" + echo " 1. Bump 'version.gradle.kts' on the base branch to the next free version." + echo " 2. Re-run this 'Publish' workflow." + echo "Stale duplicate bumps are normally caught before merge by 'revalidate-versions.yml'." diff --git a/.github/workflows/revalidate-versions.yml b/.github/workflows/revalidate-versions.yml new file mode 100644 index 00000000..2d2ecb9c --- /dev/null +++ b/.github/workflows/revalidate-versions.yml @@ -0,0 +1,57 @@ +# Re-judges every other open pull request when the base branch advances. +# +# Publishing runs on every push to a release base branch, so once one pull request merges +# and bumps the version, any other open PR that bumped to the same (or a lower) value is +# 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 +# re-bumps. The status self-clears: the re-bump push runs `increment-guard.yml`, which +# posts a fresh `success` on the new head. +# +# This narrows, but does not close, the race against auto-merge. A PR that is already +# mergeable can merge in the seconds before this fan-out marks it stale; that late merge +# produces a publish collision which the immutable Maven registry rejects (a loud, +# recoverable red Publish), never an overwrite. The deterministic guarantee is the +# registry's immutability, not this signal. + +name: Revalidate Versions + +on: + push: + # Matches the PR guard's `endsWith(base_ref, 'master'|'main')` and the same scope as + # `build-on-ubuntu.yml`. `**` (unlike `*`) also crosses `/`, so slash-named release + # lines such as `release/2.x-master` are covered. Keeping these definitions identical + # ensures every branch guarded on the PR side is also revalidated here. + branches: + - '**master' + - '**main' + +permissions: + contents: read + statuses: write + pull-requests: read + +concurrency: + # Only the newest tip of a given base matters; a later push to the same ref cancels an + # in-flight fan-out for it. Different bases run independently. + group: revalidate-versions-${{ github.ref }} + cancel-in-progress: true + +jobs: + revalidate: + name: Revalidate open PRs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: 'true' + + - name: Revalidate open PRs against the new base version + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + BASE_REF: ${{ github.ref_name }} + # Invoked via `bash` so it does not depend on the script's committed executable bit. + run: bash ./config/scripts/revalidate-versions.sh diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 1b15ab44..85d8f550 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -3,12 +3,8 @@ - - diff --git a/buildSrc/src/main/kotlin/DependencyResolution.kt b/buildSrc/src/main/kotlin/DependencyResolution.kt index 124adb3f..7d76bbba 100644 --- a/buildSrc/src/main/kotlin/DependencyResolution.kt +++ b/buildSrc/src/main/kotlin/DependencyResolution.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. @@ -30,6 +30,7 @@ import io.spine.dependency.build.Dokka import io.spine.dependency.build.ErrorProne import io.spine.dependency.build.FindBugs import io.spine.dependency.build.JSpecify +import io.spine.dependency.isDokka import io.spine.dependency.lib.Asm import io.spine.dependency.lib.AutoCommon import io.spine.dependency.lib.AutoService @@ -73,6 +74,9 @@ fun doForceVersions(configurations: ConfigurationContainer) { */ fun NamedDomainObjectContainer.forceVersions() { all { + if (isDokka) { + return@all + } resolutionStrategy { failOnVersionConflict() cacheChangingModulesFor(0, "seconds") diff --git a/buildSrc/src/main/kotlin/dokka-setup.gradle.kts b/buildSrc/src/main/kotlin/dokka-setup.gradle.kts index d34615c3..a1915cf0 100644 --- a/buildSrc/src/main/kotlin/dokka-setup.gradle.kts +++ b/buildSrc/src/main/kotlin/dokka-setup.gradle.kts @@ -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. @@ -41,6 +41,15 @@ tasks.withType().configureEach { } } +// The Dokka Javadoc format does not support Kotlin Multiplatform source sets, so its +// publication task fails for KMP modules ("No source set found for /jvmMain"). +// KMP modules publish HTML documentation, so skip the Javadoc publication for them. +plugins.withId("org.jetbrains.kotlin.multiplatform") { + tasks.matching { it.name == "dokkaGeneratePublicationJavadoc" }.configureEach { + enabled = false + } +} + afterEvaluate { dokka { configureForKotlin( diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt b/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt index 37265112..0eb1956b 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/Dependency.kt @@ -111,6 +111,17 @@ abstract class DependencyWithBom : Dependency() { fun Configuration.diagSuffix(project: Project): String = "the configuration `$name` in the project: `${project.path}`." +/** + * Tells if this configuration belongs to Dokka's own generator/plugin classpath. + * + * Dokka resolves these `dokka*` configurations using dependency versions pinned by + * Dokka itself (for example, Jackson or Kotlin), which legitimately differ from the + * project's. Forcing the project's versions onto them breaks `dokkaGenerate`, so such + * configurations must be excluded from the project's version forcing. + */ +val Configuration.isDokka: Boolean + get() = name.startsWith("dokka") + private fun ResolutionStrategy.forceWithLogging( project: Project, configuration: Configuration, diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt b/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt index c5444a00..e60d6dea 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/boms/BomsPlugin.kt @@ -29,6 +29,7 @@ package io.spine.dependency.boms import io.gitlab.arturbosch.detekt.getSupportedKotlinVersion import io.spine.dependency.DependencyWithBom import io.spine.dependency.diagSuffix +import io.spine.dependency.isDokka import io.spine.dependency.kotlinx.Coroutines import io.spine.dependency.lib.Kotlin import io.spine.dependency.test.JUnit @@ -88,7 +89,7 @@ class BomsPlugin : Plugin { applyBoms(project, Boms.core + Boms.testing) } - matching { !supportsBom(it.name) }.all { + matching { !supportsBom(it.name) && !it.isDokka }.all { resolutionStrategy.eachDependency { if (requested.group == Kotlin.group) { val kotlinVersion = Kotlin.runtimeVersion @@ -170,7 +171,7 @@ private fun supportsBom(name: String) = private fun Project.forceArtifacts() = configurations.all { resolutionStrategy { - if (!isDetekt) { + if (!isDetekt && !isDokka) { val rs = this@resolutionStrategy val project = this@forceArtifacts val cfg = this@all 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 6253c0ef..433c1bd9 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Base.kt @@ -33,8 +33,8 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName", "unused") object Base { - const val version = "2.0.0-SNAPSHOT.420" - const val versionForBuildScript = "2.0.0-SNAPSHOT.420" + const val version = "2.0.0-SNAPSHOT.421" + const val versionForBuildScript = "2.0.0-SNAPSHOT.421" 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/Compiler.kt b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt index caa002a5..8667b50e 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -72,7 +72,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.054" + private const val fallbackVersion = "2.0.0-SNAPSHOT.057" /** * The distinct version of the Compiler used by other build tools. @@ -81,7 +81,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.054" + private const val fallbackDfVersion = "2.0.0-SNAPSHOT.057" /** * 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 54029eb0..d4b8a18c 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvm.kt @@ -39,7 +39,7 @@ typealias CoreJava = CoreJvm @Suppress("ConstPropertyName", "unused") object CoreJvm { const val group = Spine.group - const val version = "2.0.0-SNAPSHOT.380" + const val version = "2.0.0-SNAPSHOT.381" 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 4754ad5b..c8d28e7f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/CoreJvmCompiler.kt @@ -46,12 +46,12 @@ object CoreJvmCompiler { /** * The version used in the build classpath. */ - const val dogfoodingVersion = "2.0.0-SNAPSHOT.079" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.080" /** * The version to be used for integration tests. */ - const val version = "2.0.0-SNAPSHOT.079" + const val version = "2.0.0-SNAPSHOT.080" /** * The ID of the Gradle plugin. 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 04d19ea5..e9f477ac 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Logging.kt @@ -33,7 +33,7 @@ package io.spine.dependency.local */ @Suppress("ConstPropertyName", "unused") object Logging { - const val version = "2.0.0-SNAPSHOT.417" + const val version = "2.0.0-SNAPSHOT.419" const val group = Spine.group const val loggingArtifact = "spine-logging" 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 d39bfb08..cd11577f 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt @@ -34,8 +34,8 @@ package io.spine.dependency.local @Suppress("ConstPropertyName", "unused") object ToolBase { const val group = Spine.toolsGroup - const val version = "2.0.0-SNAPSHOT.401" - const val dogfoodingVersion = "2.0.0-SNAPSHOT.401" + const val version = "2.0.0-SNAPSHOT.402" + const val dogfoodingVersion = "2.0.0-SNAPSHOT.402" const val lib = "$group:tool-base:$version" const val classicCodegen = "$group:classic-codegen:$version" diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/H2.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/H2.kt new file mode 100644 index 00000000..5232e63f --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/H2.kt @@ -0,0 +1,40 @@ +/* + * 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.dependency.storage + +/** + * The H2 Database Engine — a fast, in-memory/embedded SQL database used for exercising + * the JDBC storage in tests. + * + * @see H2 Database Engine at GitHub + * @see H2 Database Engine site + */ +@Suppress("unused", "ConstPropertyName") +object H2 { + private const val version = "2.4.240" + const val lib = "com.h2database:h2:$version" +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/Hikari.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/Hikari.kt new file mode 100644 index 00000000..5ab609ef --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/Hikari.kt @@ -0,0 +1,40 @@ +/* + * 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.dependency.storage + +/** + * HikariCP — a fast, lightweight JDBC connection pool. + * + * The JDBC storage uses it to pool database connections. + * + * @see HikariCP at GitHub + */ +@Suppress("unused", "ConstPropertyName") +object Hikari { + private const val version = "7.1.0" + const val lib = "com.zaxxer:HikariCP:$version" +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/HsqlDb.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/HsqlDb.kt new file mode 100644 index 00000000..3a6b509c --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/HsqlDb.kt @@ -0,0 +1,41 @@ +/* + * 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.dependency.storage + +/** + * HyperSQL DataBase (HSQLDB) — a relational database engine written in Java, used in its + * in-memory mode for exercising the JDBC storage in tests. + * + * HSQLDB is hosted on SourceForge rather than GitHub. + * + * @see HyperSQL Database site + */ +@Suppress("unused", "ConstPropertyName") +object HsqlDb { + private const val version = "2.7.4" + const val lib = "org.hsqldb:hsqldb:$version" +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/MySql.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/MySql.kt new file mode 100644 index 00000000..78bbfc3b --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/MySql.kt @@ -0,0 +1,41 @@ +/* + * 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.dependency.storage + +/** + * MySQL Connector/J — the official JDBC driver for MySQL. + * + * Used by the MySQL-based storage tests. Note the modern `com.mysql:mysql-connector-j` + * coordinates, which superseded the legacy `mysql:mysql-connector-java` artifact. + * + * @see MySQL Connector/J at GitHub + */ +@Suppress("unused", "ConstPropertyName") +object MySql { + private const val version = "9.7.0" + const val connector = "com.mysql:mysql-connector-j:$version" +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/PostgreSql.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/PostgreSql.kt new file mode 100644 index 00000000..d4083c65 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/PostgreSql.kt @@ -0,0 +1,40 @@ +/* + * 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.dependency.storage + +/** + * The PostgreSQL JDBC driver (pgJDBC). + * + * Used by the PostgreSQL-based storage tests to connect to a real PostgreSQL server. + * + * @see PostgreSQL JDBC Driver at GitHub + */ +@Suppress("unused", "ConstPropertyName") +object PostgreSql { + private const val version = "42.7.11" + const val connector = "org.postgresql:postgresql:$version" +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/storage/QueryDsl.kt b/buildSrc/src/main/kotlin/io/spine/dependency/storage/QueryDsl.kt new file mode 100644 index 00000000..e22cd9a9 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/dependency/storage/QueryDsl.kt @@ -0,0 +1,45 @@ +/* + * 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.dependency.storage + +/** + * QueryDSL — a framework for constructing type-safe SQL-like queries in Java. + * + * The JDBC storage uses the SQL module to build database queries. + * + * @see QueryDSL at GitHub + */ +@Suppress("unused", "ConstPropertyName") +object QueryDsl { + private const val version = "5.1.0" + private const val group = "com.querydsl" + + /** + * The SQL module of QueryDSL. + */ + const val sql = "$group:querydsl-sql:$version" +} diff --git a/buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt b/buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt index bb3b22e3..85c91b50 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/test/Testcontainers.kt @@ -26,12 +26,38 @@ package io.spine.dependency.test -// https://github.com/testcontainers/testcontainers-java +/** + * Testcontainers for Java — provides throwaway, lightweight instances of databases and other + * services running in Docker containers. + * + * The modules below are versioned and released together, so a single [version] applies to all + * of them. + * + * @see + * Testcontainers for Java at GitHub + */ @Suppress("unused", "ConstPropertyName") object Testcontainers { private const val version = "1.21.4" private const val group = "org.testcontainers" + + /** + * The core Testcontainers library. + */ const val lib = "$group:testcontainers:$version" + + /** + * The JUnit 5 (Jupiter) integration. + */ const val junitJupiter = "$group:junit-jupiter:$version" + + /** + * The Google Cloud (GCP) emulator container support. + */ const val gcloud = "$group:gcloud:$version" + + /** + * The MySQL container support. + */ + const val mySql = "$group:mysql:$version" } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/VersionComparator.kt b/buildSrc/src/main/kotlin/io/spine/gradle/VersionComparator.kt new file mode 100644 index 00000000..58e8aea2 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/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 + +/** + * 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/main/kotlin/io/spine/gradle/VersionGradleFile.kt b/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt new file mode 100644 index 00000000..7e86ea94 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt @@ -0,0 +1,157 @@ +/* + * 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 + +import java.io.File +import org.gradle.api.GradleException + +/** + * Reads a `version.gradle.kts` file and resolves the `extra` properties it declares. + * + * [contentUnder] and [contentInBase] read the file (from the working tree or a base branch); + * [keyForValue] and [valueForKey] resolve its `extra` properties. The following declaration + * shapes are handled (see the `bump-version` skill): + * + * 1. a literal: `val versionToPublish: String by extra("2.0.0-SNAPSHOT.182")`; + * 2. an alias to another `extra`: `val versionToPublish by extra(compilerVersion)` paired + * with `val compilerVersion: String by extra("2.0.0-SNAPSHOT.043")`; + * 3. an alias to a plain `val`: `val versionToPublish by extra(base)` paired with + * `val base = "2.0.0-SNAPSHOT.043"`. + * + * The publishing-version property is identified by [keyForValue] using the already-resolved + * project version as an oracle, so the specific property name (`versionToPublish`, + * `validationVersion`, `compilerVersion`, …) does not need to be hard-coded. + * + * Only a single alias hop is resolved; an alias to another alias falls through to `null`, + * which the caller treats as "publishing version not identified" and skips the check. + */ +internal object VersionGradleFile { + + /** + * The name of a `version.gradle.kts` file. + */ + const val NAME = "version.gradle.kts" + + private val literalExtra = + Regex("""val\s+(\w+)\s*(?::\s*String)?\s+by\s+extra\(\s*"([^"]+)"\s*\)""") + private val aliasExtra = + Regex("""val\s+(\w+)\s*(?::\s*String)?\s+by\s+extra\(\s*([A-Za-z_]\w*)\s*\)""") + private val plainAssignment = + Regex("""val\s+(\w+)\s*(?::\s*String)?\s*=\s*"([^"]+)"""") + + /** + * Resolves every named `extra` (and the plain `val`s an `extra` may alias) to its + * string value. + */ + private fun parse(content: String): Map { + val literals = literalExtra.findAll(content) + .associate { it.groupValues[1] to it.groupValues[2] } + val plains = plainAssignment.findAll(content) + .associate { it.groupValues[1] to it.groupValues[2] } + val resolved = literals.toMutableMap() + aliasExtra.findAll(content).forEach { match -> + val name = match.groupValues[1] + val source = match.groupValues[2] + if (name !in resolved) { + (literals[source] ?: plains[source])?.let { resolved[name] = it } + } + } + return resolved + } + + /** + * The name of the property whose resolved value equals [value], or `null` if none does. + */ + fun keyForValue(content: String, value: String): String? = + parse(content).entries.firstOrNull { it.value == value }?.key + + /** + * The resolved value of the property named [key], or `null` if it is absent. + */ + fun valueForKey(content: String, key: String): String? = parse(content)[key] + + /** + * Reads `version.gradle.kts` from [rootDir], or `null` when it is absent. + */ + fun contentUnder(rootDir: File): String? = + File(rootDir, NAME).takeIf { it.exists() }?.readText() + + /** + * Reads `version.gradle.kts` from the tip of the `origin/` remote-tracking branch. + * + * Returns `null` when the file does not exist at the base — a newly introduced version file. + * Throws a [GradleException] when the base ref cannot be resolved: the Version Guard workflow + * is responsible for fetching it, and failing closed surfaces that misconfiguration instead + * of silently passing the check. + */ + fun contentInBase(rootDir: File, baseRef: String): String? { + val result = gitShow(rootDir, "origin/$baseRef:$NAME") + if (result.exitCode == 0) { + return result.stdout + } + // `git show` reports a missing path with these phrasings; everything else + // (e.g. an unresolvable ref) is a configuration error we must not swallow. + val missingPath = result.stderr.contains("does not exist") || + result.stderr.contains("exists on disk, but not in") + if (missingPath) { + return null + } + throw GradleException( + "Unable to read `$NAME` from base `origin/$baseRef` " + + "(git exit code ${result.exitCode}): ${result.stderr.trim()}.\n" + + "Ensure the Version Guard workflow fetches the base branch before this check." + ) + } +} + +/** + * The outcome of a `git` invocation: its [exitCode] and the captured [stdout] and [stderr]. + * + * @property exitCode The process exit code; `0` on success. + * @property stdout The captured standard output stream. + * @property stderr The captured standard error stream. + */ +private data class GitResult(val exitCode: Int, val stdout: String, val stderr: String) + +private fun gitShow(rootDir: File, spec: String): GitResult { + // Redirect to files rather than reading the process pipes sequentially: draining + // stdout fully before stderr can deadlock if a stream fills its pipe buffer. + val outFile = File.createTempFile("git-show", ".out") + val errFile = File.createTempFile("git-show", ".err") + try { + val exitCode = ProcessBuilder("git", "show", spec) + .directory(rootDir) + .redirectOutput(outFile) + .redirectError(errFile) + .start() + .waitFor() + return GitResult(exitCode, outFile.readText(), errFile.readText()) + } finally { + outFile.delete() + errFile.delete() + } +} diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/kotlin/KotlinConfig.kt b/buildSrc/src/main/kotlin/io/spine/gradle/kotlin/KotlinConfig.kt index 92b7a387..0e5099a7 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/kotlin/KotlinConfig.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/kotlin/KotlinConfig.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. @@ -55,20 +55,26 @@ fun KotlinJvmProjectExtension.applyJvmToolchain(version: String) = */ @Suppress("unused") fun KotlinCommonCompilerOptions.setFreeCompilerArgs() { + val optIns = mutableListOf( + "kotlin.contracts.ExperimentalContracts", + "kotlin.ExperimentalUnsignedTypes", + "kotlin.ExperimentalStdlibApi", + "kotlin.experimental.ExperimentalTypeInference", + ) if (this is KotlinJvmCompilerOptions) { jvmDefault.set(JvmDefaultMode.NO_COMPATIBILITY) + // `kotlin.io.path` ships only in the JVM standard library, so for common + // and Native compilations this opt-in marker is unresolved and the compiler + // warns about it. Scope it to JVM compilations; multiplatform common and + // Native code cannot use the API anyway. + optIns.add("kotlin.io.path.ExperimentalPathApi") } freeCompilerArgs.addAll( listOf( "-Xskip-prerelease-check", "-Xexpect-actual-classes", "-Xcontext-parameters", - "-opt-in=" + - "kotlin.contracts.ExperimentalContracts," + - "kotlin.io.path.ExperimentalPathApi," + - "kotlin.ExperimentalUnsignedTypes," + - "kotlin.ExperimentalStdlibApi," + - "kotlin.experimental.ExperimentalTypeInference", + "-opt-in=" + optIns.joinToString(separator = ","), ) ) } diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt index 4c215f14..16897ffd 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/CheckVersionIncrement.kt @@ -26,12 +26,10 @@ package io.spine.gradle.publish -import com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES -import com.fasterxml.jackson.dataformat.xml.XmlMapper +import io.spine.gradle.VersionComparator +import io.spine.gradle.VersionGradleFile import io.spine.gradle.repo.Repository -import java.io.FileNotFoundException import java.net.URI -import java.net.URL import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.Project @@ -39,8 +37,20 @@ import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction /** - * A task that verifies that the current version of the library has not been published to the given - * Maven repository yet. + * A task that verifies the project version is fit to be published. + * + * Two independent checks run: + * + * 1. [checkIncrementedAgainstBase] — inside the dedicated `Version Guard` workflow, the + * project [version] must be strictly greater than the version declared by + * `version.gradle.kts` on the PR's base branch. This is deterministic and + * network-independent: it catches a behavior-changing PR that forgot to bump, and two + * parallel PRs that bumped to the same value, regardless of what is (or is not yet) + * published. + * 2. [checkNotPublished] — the [version] must not already exist in the target Maven + * repository, so a publication cannot overwrite an immutable artifact. + * + * The two checks are complementary; neither subsumes the other. */ open class CheckVersionIncrement : DefaultTask() { @@ -57,7 +67,111 @@ open class CheckVersionIncrement : DefaultTask() { val version: String = project.version as String @TaskAction - fun fetchAndCheck() { + fun checkVersion() { + checkIncrementedAgainstBase() + checkNotPublished() + } + + /** + * Verifies that the project [version] is strictly greater than the version declared by + * `version.gradle.kts` on the pull request's base branch. + * + * The comparison reads the base branch tip with `git show origin/:version.gradle.kts`, + * so it runs **only inside the dedicated `Version Guard` workflow** — the one context that + * fetches the base ref and signals it via the `VERSION_GUARD` environment variable (see + * [IncrementGuard.shouldCompareToBase]). Every other build skips it: a shallow CI checkout + * (e.g. the Ubuntu/Windows builds, which pull this task in via `publishToMavenLocal`) has + * no base ref to read, and local publishes are not pull requests. Those rely on + * [checkNotPublished] instead. + * + * Within the `Version Guard` workflow, failure modes are deliberately asymmetric: + * - base ref unresolvable — **fail closed** (a workflow misconfiguration must not pass + * silently); + * - `version.gradle.kts` absent on base — treated as a newly introduced file (**pass**); + * - the publishing-version property cannot be identified — **skip** with a warning, + * leaving [checkNotPublished] as the remaining guard, rather than blocking every PR in + * a repository whose `version.gradle.kts` uses an unrecognized shape. + */ + private fun checkIncrementedAgainstBase() { + val baseRef = System.getenv("GITHUB_BASE_REF") + if (!IncrementGuard.shouldCompareToBase(underVersionGuard(), baseRef)) { + logger.info( + "Skipping the base-branch increment comparison: it runs only inside the " + + "`Version Guard` workflow, which fetches the base branch. " + + "`checkNotPublished` remains the active guard here." + ) + return + } + val baseVersion = baseVersionToCompare( + checkNotNull(baseRef) { "`shouldCompareToBase` guarantees a non-blank base ref." } + ) + if (baseVersion != null && VersionComparator.compare(version, baseVersion) <= 0) { + throw GradleException( + """ + The project version `$version` is not greater than the base branch version + `$baseVersion` (base `$baseRef`). + + A pull request that merges into `$baseRef` must increment the version in + `${VersionGradleFile.NAME}`. Publishing runs on every push to the base branch, + so a non-incremented version would collide with the already-published artifact. + + Bump the version (e.g. run `/bump-version`) and push again. + + To disable this check, run Gradle with `-x $name`. + """.trimIndent() + ) + } + } + + /** + * Tells whether the build runs inside the dedicated `Version Guard` workflow. + * + * That workflow fetches the base branch before invoking this task and signals it by + * setting the `VERSION_GUARD` environment variable to `true`. The variable is the + * authoritative marker that `origin/` is present, so the base-branch comparison + * may run; see [IncrementGuard.shouldCompareToBase]. + */ + private fun underVersionGuard(): Boolean = + "true".equals(System.getenv("VERSION_GUARD")) + + /** + * Resolves the base-branch publishing version to compare [version] against, or `null` + * when the comparison does not apply. + * + * Returns `null` (skipping the check) when the publishing-version property cannot be + * identified in the working-tree `version.gradle.kts`, or when the base branch has no + * comparable value (the file is absent or newly introduced). Throws via + * [VersionGradleFile.contentInBase] when the base ref itself cannot be resolved. + */ + private fun baseVersionToCompare(baseRef: String): String? { + val headContent = VersionGradleFile.contentUnder(project.rootDir) + val key = headContent?.let { VersionGradleFile.keyForValue(it, version) } + if (key == null) { + logger.warn( + "Could not identify the publishing-version property matching `$version` in " + + "`${VersionGradleFile.NAME}`; skipping the base-branch increment check." + ) + return null + } + val baseContent = VersionGradleFile.contentInBase(project.rootDir, baseRef) + val baseVersion = baseContent?.let { VersionGradleFile.valueForKey(it, key) } + if (baseVersion == null) { + logger.info( + "No comparable `$key` in `${VersionGradleFile.NAME}` on base `$baseRef` " + + "(absent or newly introduced); skipping the base-branch increment check." + ) + } + return baseVersion + } + + /** + * Verifies that the current [version] has not been published to the target Maven + * repository yet. + * + * Both the `releases` and `snapshots` repositories are checked; artifacts in either + * may not be overwritten. + */ + private fun checkNotPublished() { val artifact = "${project.artifactPath()}/${MavenMetadata.FILE_NAME}" val snapshots = repository.target(snapshots = true) checkInRepo(snapshots, artifact) @@ -76,7 +190,7 @@ open class CheckVersionIncrement : DefaultTask() { """ The version `$version` is already published to the Maven repository `$repoUrl`. Try incrementing the library version. - All available versions are: ${versions?.joinToString(separator = ", ")}. + All available versions are: ${versions.joinToString(separator = ", ")}. To disable this check, run Gradle with `-x $name`. """.trimIndent() @@ -114,34 +228,3 @@ open class CheckVersionIncrement : DefaultTask() { return result } } - -private data class MavenMetadata(var versioning: Versioning = Versioning()) { - - companion object { - - const val FILE_NAME = "maven-metadata.xml" - - private val mapper = XmlMapper() - - init { - mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false) - } - - /** - * Fetches the metadata for the repository and parses the document. - * - *

If the document could not be found, assumes that the module was never - * released and thus has no metadata. - */ - fun fetchAndParse(url: URL): MavenMetadata? { - return try { - val metadata = mapper.readValue(url, MavenMetadata::class.java) - metadata - } catch (_: FileNotFoundException) { - null - } - } - } -} - -private data class Versioning(var versions: List = listOf()) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt index 24d6d0e2..ddda57e7 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/IncrementGuard.kt @@ -28,14 +28,21 @@ package io.spine.gradle.publish +import io.spine.gradle.Build import io.spine.gradle.SpineTaskGroup import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.publish.maven.tasks.PublishToMavenLocal /** - * Gradle plugin that adds a [CheckVersionIncrement] task. + * Gradle plugin that adds a [CheckVersionIncrement] task verifying that the + * project version was incremented before its artifacts are published. * - * The task is called `checkVersionIncrement` inserted before the `check` task. + * The task — named `checkVersionIncrement` — is run directly by the `Version Guard` + * CI workflow and before any `publishToMavenLocal` task. It is deliberately kept out + * of the `check` lifecycle, and actually executes only when the verification is + * meaningful; see [apply]. */ class IncrementGuard : Plugin { @@ -57,40 +64,114 @@ class IncrementGuard : Plugin { } return baseBranch.endsWith("master") || baseBranch.endsWith("main") } + + /** + * Tells whether the [CheckVersionIncrement] action must actually run for + * the current build. + * + * The increment is verified in two situations: + * 1. [ciPullRequest] — a CI pull request that must check the version + * (see [shouldCheckVersion]); or + * 2. a local build (not [onCi]) that is going to publish to Maven Local + * ([localPublish]). + * + * CI pushes and tag builds that publish to Maven Local — e.g. to feed + * integration tests — deliberately skip the check, so that re-publishing + * an already released version does not fail them. + */ + internal fun mustVerify( + ciPullRequest: Boolean, + onCi: Boolean, + localPublish: Boolean, + ): Boolean = ciPullRequest || (!onCi && localPublish) + + /** + * Tells whether [CheckVersionIncrement] should compare the project version against + * the base branch. + * + * The comparison reads `origin/:version.gradle.kts`, so it needs the base + * branch to have been fetched. Only the dedicated `Version Guard` workflow fetches it + * and sets the `VERSION_GUARD` environment variable, which [CheckVersionIncrement] + * passes here as the [underVersionGuard] flag; the workflow runs for pull requests, so + * a non-blank [baseRef] is required as well. + * + * Every other CI build (e.g. the Ubuntu and Windows builds) pulls the check into the + * task graph through `publishToMavenLocal` but runs a shallow checkout without the + * base ref. Such builds report `underVersionGuard = false`, so the comparison is + * skipped and `checkNotPublished` stays the guard — otherwise the comparison would + * fail closed on `origin/` and break every pull request. + */ + internal fun shouldCompareToBase(underVersionGuard: Boolean, baseRef: String?): Boolean = + underVersionGuard && !baseRef.isNullOrBlank() + + /** + * Tells whether [tasks] contains a Maven Local publishing task that + * belongs to the given [project]. + * + * The scan is limited to [project]'s own publications so that, in a + * multi-project build, a sibling module's `publishToMavenLocal` does not + * trigger this module's check — which would verify an unrelated version. + */ + internal fun localPublishPlanned(tasks: Iterable, project: Project): Boolean = + tasks.any { it is PublishToMavenLocal && it.project == project } } /** - * Adds the [CheckVersionIncrement] task to the project. + * Adds the [CheckVersionIncrement] task to the [target] project and makes every + * `publishToMavenLocal` task depend on it, so that a local publish — used by + * integration tests that consume artifacts from `~/.m2` — cannot overwrite an + * already published version. + * + * The CI pull-request increment check is driven separately by the `Version Guard` + * workflow (`increment-guard.yml`), which invokes `checkVersionIncrement` by name after + * fetching the base branch and setting `VERSION_GUARD` — the signal that gates + * [CheckVersionIncrement]'s strict base-branch comparison (see [shouldCompareToBase]). + * The task is intentionally not wired into the `check` lifecycle: the version check + * belongs to the publishing path, not to generic `check` runs. A build that still pulls + * the task in through `publishToMavenLocal` (e.g. the Ubuntu/Windows CI builds, which + * publish locally to feed integration tests) stays green, because the base comparison — + * which reads `origin/` and would otherwise fail closed on a shallow checkout — is + * skipped outside the `Version Guard` workflow. * - * The task is created anyway, but it is enabled only if: - * 1. The project is built on GitHub CI, and - * 2. The job is a pull request targeting a default (`master` or `main`) or - * a release-line (e.g. `2.x-jdk8-master`) branch. + * The task is always created and wired, but its action runs only when: + * 1. the build is a GitHub Actions pull request targeting a default + * (`master` or `main`) or a release-line (e.g. `2.x-jdk8-master`) branch; or + * 2. the build runs locally (outside CI) and is going to publish artifacts + * to Maven Local. * * It is the responsibility of a branch that aims to merge into a default * (or otherwise protected) branch to bump the version. Auxiliary branches do not * deal with the versions in the release cycle, so pull requests targeting them, - * direct pushes, and tag builds do not run the check. This also prevents unexpected - * CI fails when re-building `master` multiple times, creating git tags, and in other - * cases that go outside the "usual" development cycle. + * direct pushes, and tag builds do not run the check. In particular, the + * Maven Local guard is restricted to local builds: re-building `master`, + * creating git tags, and other CI jobs that publish locally (e.g. to feed + * integration tests) keep succeeding even though their version is already + * published. Ordinary local builds that do not publish stay free from the + * network-bound version check as well. */ override fun apply(target: Project) { val tasks = target.tasks - tasks.register(taskName, CheckVersionIncrement::class.java) { + val checkVersion = tasks.register(taskName, CheckVersionIncrement::class.java) { group = SpineTaskGroup.name description = "Verifies that the project version was incremented before publishing" repository = CloudArtifactRegistry.repository - tasks.getByName("check").dependsOn(this) - - if (!shouldCheckVersion()) { - logger.info( - "The build does not represent a GitHub Actions pull request job " + - "targeting a default or a release-line branch, " + - "the `checkVersionIncrement` task is disabled." - ) - this.enabled = false + onlyIf { + mustVerify(shouldCheckVersion(), Build.ci, it.publishesToMavenLocal()) } } + + // The CI pull-request increment check is run by the `Version Guard` workflow, + // which calls `checkVersionIncrement` directly after fetching the base branch. + // It is intentionally not a dependency of `check`: that would run it in every + // `./gradlew build` (e.g. the Ubuntu/Windows CI builds), where `origin/` + // is not fetched and the fail-closed base comparison would break the build. + + // Verify before publishing to Maven Local: integration tests in this and + // sibling projects consume the freshly published artifacts from `~/.m2`, so a + // non-incremented version would let them pick up a stale artifact. + tasks.withType(PublishToMavenLocal::class.java).configureEach { + dependsOn(checkVersion) + } } /** @@ -110,3 +191,20 @@ class IncrementGuard : Plugin { return shouldCheckVersion(event, baseBranch) } } + +/** + * Tells whether the current build is going to publish this task's project to + * Maven Local. + * + * Integration tests in this and sibling projects consume freshly built artifacts + * from `~/.m2`. Publishing them under a version that already exists would let those + * tests pick up a stale artifact, so the version increment must be verified before + * any local publication runs. + * + * Only this task's own project is considered: a sibling module's local publish in + * the same invocation must not trigger this module's check. The predicate is + * evaluated lazily as a task `onlyIf` spec, by which point the execution + * [task graph][org.gradle.api.execution.TaskExecutionGraph] is fully populated. + */ +private fun Task.publishesToMavenLocal(): Boolean = + IncrementGuard.localPublishPlanned(project.gradle.taskGraph.allTasks, project) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt b/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt new file mode 100644 index 00000000..3d4906d2 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/publish/MavenMetadata.kt @@ -0,0 +1,84 @@ +/* + * 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.publish + +import com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES +import com.fasterxml.jackson.dataformat.xml.XmlMapper +import java.io.FileNotFoundException +import java.net.URL + +/** + * A minimal model of a Maven `maven-metadata.xml` document, exposing the published + * versions of an artifact. + * + * Instances are produced by [XmlMapper] from a registry response; only the `` + * element is mapped, and unknown elements are ignored. + * + * @property versioning The `` element holding the list of published versions. + * It is `var` with a default value purely to support deserialization: `buildSrc` uses a + * plain [XmlMapper] without the Kotlin module, so Jackson instantiates this class through + * the synthesized no-arg constructor and then assigns the property through its setter. The + * mutability is required by Jackson, not used by our own code; a `val` would silently + * leave the version list empty. + */ +internal data class MavenMetadata(var versioning: Versioning = Versioning()) { + + companion object { + + const val FILE_NAME = "maven-metadata.xml" + + private val mapper = XmlMapper() + + init { + mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false) + } + + /** + * Fetches the metadata for the repository and parses the document. + * + * If the document could not be found, assumes that the module was never + * released and thus has no metadata. + */ + fun fetchAndParse(url: URL): MavenMetadata? { + return try { + val metadata = mapper.readValue(url, MavenMetadata::class.java) + metadata + } catch (_: FileNotFoundException) { + null + } + } + } +} + +/** + * The `` element of a `maven-metadata.xml` document, listing the published versions. + * + * @property versions The published version strings. It is `var` for the same reason as + * [MavenMetadata.versioning]: Jackson assigns it through the setter during deserialization + * (`buildSrc` has no Kotlin module), so a `val` would leave it empty. + */ +internal data class Versioning(var versions: List = listOf()) 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 db2bf761..64e46ef7 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 @@ -27,6 +27,7 @@ package io.spine.gradle.report.pom import groovy.xml.MarkupBuilder +import io.spine.gradle.VersionComparator import java.io.Writer import java.util.* import kotlin.reflect.full.isSubclassOf diff --git a/buildSrc/src/main/kotlin/jvm-module.gradle.kts b/buildSrc/src/main/kotlin/jvm-module.gradle.kts index a7b31130..8e777c6a 100644 --- a/buildSrc/src/main/kotlin/jvm-module.gradle.kts +++ b/buildSrc/src/main/kotlin/jvm-module.gradle.kts @@ -29,6 +29,7 @@ import io.spine.dependency.build.CheckerFramework import io.spine.dependency.build.Dokka import io.spine.dependency.build.ErrorProne import io.spine.dependency.build.JSpecify +import io.spine.dependency.isDokka import io.spine.dependency.lib.Guava import io.spine.dependency.lib.Jackson import io.spine.dependency.lib.Kotlin @@ -132,6 +133,9 @@ fun Module.forceConfigurations() { forceVersions() excludeProtobufLite() all { + if (isDokka) { + return@all + } resolutionStrategy { val cfg = this@all val rs = this@resolutionStrategy diff --git a/buildSrc/src/main/kotlin/kmp-module.gradle.kts b/buildSrc/src/main/kotlin/kmp-module.gradle.kts index a2e6d82e..636a84d2 100644 --- a/buildSrc/src/main/kotlin/kmp-module.gradle.kts +++ b/buildSrc/src/main/kotlin/kmp-module.gradle.kts @@ -25,6 +25,7 @@ */ import io.spine.dependency.boms.BomsPlugin +import io.spine.dependency.isDokka import io.spine.dependency.lib.Jackson import io.spine.dependency.lib.Kotlin import io.spine.dependency.local.Reflect @@ -83,6 +84,9 @@ fun Project.forceConfigurations() { with(configurations) { forceVersions() all { + if (isDokka) { + return@all + } resolutionStrategy { val cfg = this@all val rs = this@resolutionStrategy diff --git a/buildSrc/src/main/kotlin/module.gradle.kts b/buildSrc/src/main/kotlin/module.gradle.kts index d714d087..bb5572d9 100644 --- a/buildSrc/src/main/kotlin/module.gradle.kts +++ b/buildSrc/src/main/kotlin/module.gradle.kts @@ -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. @@ -160,17 +160,20 @@ fun Module.configureGitHubPages() { /** * Adds directories with the generated source code to source sets of the project. * + * Generated Kotlin sources are intentionally not added here: the + * `io.spine.generated-sources` plugin registers them under the Kotlin Gradle plugin's + * dedicated `generatedKotlin` source set, keeping them out of the plain `kotlin` set + * so that build tooling and IDEs can tell them apart from hand-written code. + * * @param generatedDir The name of the root directory with the generated code */ fun Module.applyGeneratedDirectories(generatedDir: String) { val generatedMain = "$generatedDir/main" val generatedJava = "$generatedMain/java" - val generatedKotlin = "$generatedMain/kotlin" val generatedGrpc = "$generatedMain/grpc" val generatedTest = "$generatedDir/test" val generatedTestJava = "$generatedTest/java" - val generatedTestKotlin = "$generatedTest/kotlin" val generatedTestGrpc = "$generatedTest/grpc" sourceSets { @@ -179,18 +182,12 @@ fun Module.applyGeneratedDirectories(generatedDir: String) { generatedJava, generatedGrpc, ) - kotlin.srcDirs( - generatedKotlin, - ) } test { java.srcDirs( generatedTestJava, generatedTestGrpc, ) - kotlin.srcDirs( - generatedTestKotlin, - ) } } } diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/VersionComparatorSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/VersionComparatorSpec.kt new file mode 100644 index 00000000..c643645b --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/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 + +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/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt new file mode 100644 index 00000000..e76febe2 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt @@ -0,0 +1,86 @@ +/* + * 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 + +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`VersionGradleFile` should read the publishing version") +internal class VersionGradleFileSpec { + + @Test + fun `declared as a literal`() { + val content = """ + val versionToPublish: String by extra("2.0.0-SNAPSHOT.182") + """.trimIndent() + + VersionGradleFile.keyForValue(content, "2.0.0-SNAPSHOT.182") shouldBe "versionToPublish" + VersionGradleFile.valueForKey(content, "versionToPublish") shouldBe "2.0.0-SNAPSHOT.182" + } + + @Test + fun `declared as an alias to another 'extra'`() { + val content = """ + val compilerVersion: String by extra("2.0.0-SNAPSHOT.043") + val versionToPublish by extra(compilerVersion) + """.trimIndent() + + VersionGradleFile.valueForKey(content, "versionToPublish") shouldBe "2.0.0-SNAPSHOT.043" + VersionGradleFile.valueForKey(content, "compilerVersion") shouldBe "2.0.0-SNAPSHOT.043" + } + + @Test + fun `declared as an alias to a plain 'val'`() { + val content = """ + val base = "2.0.0-SNAPSHOT.043" + val versionToPublish by extra(base) + """.trimIndent() + + VersionGradleFile.valueForKey(content, "versionToPublish") shouldBe "2.0.0-SNAPSHOT.043" + } + + @Test + fun `identified by the resolved project version, not a hard-coded name`() { + val content = """ + val kotlinVersion: String by extra("2.1.0") + val versionToPublish: String by extra("2.0.0-SNAPSHOT.182") + """.trimIndent() + + VersionGradleFile.keyForValue(content, "2.0.0-SNAPSHOT.182") shouldBe "versionToPublish" + } + + @Test + fun `absent when no property matches`() { + val content = """ + val versionToPublish: String by extra("2.0.0-SNAPSHOT.182") + """.trimIndent() + + VersionGradleFile.keyForValue(content, "9.9.9") shouldBe null + VersionGradleFile.valueForKey(content, "missing") shouldBe null + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt index 5633c30d..7b317c94 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/IncrementGuardTest.kt @@ -26,8 +26,17 @@ package io.spine.gradle.publish +import io.kotest.matchers.collections.shouldContain +import io.kotest.matchers.collections.shouldNotContain import io.kotest.matchers.shouldBe +import io.spine.gradle.publish.IncrementGuard.Companion.localPublishPlanned +import io.spine.gradle.publish.IncrementGuard.Companion.mustVerify import io.spine.gradle.publish.IncrementGuard.Companion.shouldCheckVersion +import io.spine.gradle.publish.IncrementGuard.Companion.shouldCompareToBase +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.publish.maven.tasks.PublishToMavenLocal +import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test @@ -76,4 +85,138 @@ class IncrementGuardTest { shouldCheckVersion(null, null) shouldBe false } } + + @Nested + inner class `actually run the check` { + + @Test + fun `on a CI pull request to a protected branch`() { + mustVerify(ciPullRequest = true, onCi = true, localPublish = false) shouldBe true + } + + @Test + fun `on a local build that publishes to Maven Local`() { + mustVerify(ciPullRequest = false, onCi = false, localPublish = true) shouldBe true + } + } + + @Nested + inner class `skip the check` { + + @Test + fun `on a local build that does not publish`() { + mustVerify(ciPullRequest = false, onCi = false, localPublish = false) shouldBe false + } + + @Test + fun `on a CI build that publishes to Maven Local outside a protected-branch PR`() { + // E.g. a push to `master` or a tag build running integration tests: the + // version is already published, so re-verifying it would fail the build. + mustVerify(ciPullRequest = false, onCi = true, localPublish = true) shouldBe false + } + } + + @Nested + inner class `compare against the base branch` { + + @Test + fun `inside the Version Guard workflow with a base branch`() { + shouldCompareToBase(underVersionGuard = true, baseRef = "master") shouldBe true + shouldCompareToBase(underVersionGuard = true, baseRef = "2.x-jdk8-master") shouldBe true + } + } + + @Nested + inner class `not compare against the base branch` { + + @Test + fun `outside the Version Guard workflow`() { + // The Ubuntu/Windows CI builds pull the task in via `publishToMavenLocal`, + // but they never fetch the base ref, so `VERSION_GUARD` is unset. + shouldCompareToBase(underVersionGuard = false, baseRef = "master") shouldBe false + } + + @Test + fun `when no base branch is present`() { + shouldCompareToBase(underVersionGuard = true, baseRef = null) shouldBe false + shouldCompareToBase(underVersionGuard = true, baseRef = "") shouldBe false + } + } + + @Nested + inner class `detect a Maven Local publish` { + + @Test + fun `for the task's own project`() { + val project = guardedProject() + val publish = project.tasks + .register("publishFooPublicationToMavenLocal", PublishToMavenLocal::class.java) + .get() + + localPublishPlanned(listOf(publish), project) shouldBe true + } + + @Test + fun `but not when only a sibling project publishes`() { + val root = ProjectBuilder.builder().build() + val lib = ProjectBuilder.builder().withParent(root).withName("lib").build() + val app = ProjectBuilder.builder().withParent(root).withName("app").build() + app.pluginManager.apply("maven-publish") + val appPublish = app.tasks + .register("publishFooPublicationToMavenLocal", PublishToMavenLocal::class.java) + .get() + + localPublishPlanned(listOf(appPublish), lib) shouldBe false + } + } + + @Nested + inner class `make 'checkVersionIncrement' a dependency of` { + + @Test + fun `every Maven Local publishing task`() { + val project = guardedProject() + val localPublish = project.tasks.register( + "publishFooPublicationToMavenLocal", + PublishToMavenLocal::class.java + ).get() + + localPublish.dependencyNames() shouldContain IncrementGuard.taskName + } + } + + @Nested + inner class `keep 'checkVersionIncrement' out of` { + + @Test + fun `the 'check' lifecycle task`() { + // The CI check runs via the `Version Guard` workflow, which fetches the + // base branch first. Wiring it into `check` would run it in every + // `./gradlew build`, where `origin/` is absent and the fail-closed + // base comparison would break the build. + val project = guardedProject() + val check = project.tasks.getByName("check") + + check.dependencyNames() shouldNotContain IncrementGuard.taskName + } + } } + +/** + * Creates a project with the `base` plugin (for the `check` task), the + * `maven-publish` plugin (for [PublishToMavenLocal] tasks), and [IncrementGuard] + * applied. + */ +private fun guardedProject(): Project { + val project = ProjectBuilder.builder().build() + project.pluginManager.apply("base") + project.pluginManager.apply("maven-publish") + project.pluginManager.apply(IncrementGuard::class.java) + return project +} + +/** + * Obtains the names of the tasks this task directly depends on. + */ +private fun Task.dependencyNames(): Set = + taskDependencies.getDependencies(this).map { it.name }.toSet() diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/publish/MavenMetadataSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/publish/MavenMetadataSpec.kt new file mode 100644 index 00000000..39f8a510 --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/publish/MavenMetadataSpec.kt @@ -0,0 +1,53 @@ +/* + * 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.publish + +import com.fasterxml.jackson.dataformat.xml.XmlMapper +import io.kotest.matchers.collections.shouldContainExactly +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`MavenMetadata` should") +internal class MavenMetadataSpec { + + /** + * Round-trips through the same [XmlMapper] used in production, asserting the version list + * survives. This guards the `var` properties of [MavenMetadata] and [Versioning]: a `val` + * (or `internal`-mangled setter) would leave the list empty after deserialization, silently + * disabling the "already published" check. + */ + @Test + fun `survive a Jackson round-trip, keeping its versions`() { + val versions = listOf("2.0.0-SNAPSHOT.79", "2.0.0-SNAPSHOT.80", "2.0.0-SNAPSHOT.81") + val mapper = XmlMapper() + + val xml = mapper.writeValueAsString(MavenMetadata(Versioning(versions))) + val parsed = mapper.readValue(xml, MavenMetadata::class.java) + + parsed.versioning.versions shouldContainExactly versions + } +} diff --git a/config b/config index 0728520a..ad5e32ea 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit 0728520aa2b6e418d9908ca226c2d331c8d94c83 +Subproject commit ad5e32ea3007b506ca796ff70a91e5d1f2d805a3 diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index 55e9b666..569481da 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine.tools:classic-codegen:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:classic-codegen:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -143,6 +143,10 @@ * **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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -151,6 +155,10 @@ * **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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -493,6 +501,10 @@ * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -649,6 +661,10 @@ * **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-stdlib-jdk7. **Version** : 1.8.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk7. **Version** : 2.0.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -657,6 +673,10 @@ * **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-stdlib-jdk8. **Version** : 1.8.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk8. **Version** : 2.0.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -681,10 +701,18 @@ * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-bom. **Version** : 1.7.3. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core. **Version** : 1.10.2. * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core. **Version** : 1.7.3. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core-jvm. **Version** : 1.10.2. * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -693,6 +721,10 @@ * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core-jvm. **Version** : 1.7.3. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-jdk8. **Version** : 1.10.2. * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -705,11 +737,11 @@ * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -828,14 +860,14 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:gradle-plugin-api:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:gradle-plugin-api:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.0. @@ -929,11 +961,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1036,6 +1068,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1044,6 +1080,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1375,6 +1415,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1607,11 +1651,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1734,14 +1778,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:gradle-plugin-api-test-fixtures:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:gradle-plugin-api-test-fixtures:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.0. @@ -1835,11 +1879,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2185,11 +2229,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2212,14 +2256,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:33 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:gradle-root-plugin:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:gradle-root-plugin:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -2289,11 +2333,11 @@ This report was generated on **Wed Jun 24 19:40:33 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2368,6 +2412,10 @@ This report was generated on **Wed Jun 24 19:40:33 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2376,6 +2424,10 @@ This report was generated on **Wed Jun 24 19:40:33 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2707,6 +2759,10 @@ This report was generated on **Wed Jun 24 19:40:33 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2947,11 +3003,11 @@ This report was generated on **Wed Jun 24 19:40:33 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3070,14 +3126,14 @@ This report was generated on **Wed Jun 24 19:40:33 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:intellij-platform:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:intellij-platform:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -3356,6 +3412,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3364,6 +3424,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3741,6 +3805,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4019,11 +4087,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4151,14 +4219,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:intellij-platform-java:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:intellij-platform-java:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -4838,6 +4906,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4846,6 +4918,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5442,6 +5518,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5745,11 +5825,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -5930,14 +6010,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:46 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.tools:jvm-tool-plugins:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:jvm-tool-plugins:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -6007,11 +6087,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -6086,6 +6166,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -6094,6 +6178,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -6425,6 +6513,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -6657,11 +6749,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -6780,14 +6872,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:jvm-tools:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:jvm-tools:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. @@ -6877,6 +6969,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -6885,6 +6981,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -7212,6 +7312,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -7424,11 +7528,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -7547,14 +7651,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:plugin-base:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:plugin-base:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -7624,11 +7728,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -7703,6 +7807,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -7711,6 +7819,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -8050,6 +8162,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -8282,11 +8398,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -8405,14 +8521,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:plugin-testlib:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:plugin-testlib:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.google.auto.value. **Name** : auto-value-annotations. **Version** : 1.11.1. @@ -8573,11 +8689,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -8673,6 +8789,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -8681,6 +8801,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -9012,6 +9136,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -9244,11 +9372,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -9367,14 +9495,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:protobuf-setup-plugins:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:protobuf-setup-plugins:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -9456,11 +9584,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -9535,6 +9663,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -9543,6 +9675,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -9882,6 +10018,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10114,11 +10254,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10237,14 +10377,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:psi:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:psi:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -10550,6 +10690,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10558,6 +10702,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -10935,6 +11083,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -11213,11 +11365,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -11345,14 +11497,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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.tools:psi-java:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:psi-java:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : be.cyberelf.nanoxml. **Name** : nanoxml. **Version** : 2.2.3. @@ -12051,6 +12203,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12059,6 +12215,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12659,6 +12819,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -12982,11 +13146,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13167,14 +13331,14 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:46 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.tools:tool-base:2.0.0-SNAPSHOT.402` +# Dependencies of `io.spine.tools:tool-base:2.0.0-SNAPSHOT.403` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -13244,11 +13408,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13331,6 +13495,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.code.gson. **Name** : gson. **Version** : 2.8.9. + * **Project URL:** [https://github.com/google/gson/gson](https://github.com/google/gson/gson) + * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : com.google.errorprone. **Name** : error_prone_annotation. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_annotation](https://errorprone.info/error_prone_annotation) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13339,6 +13507,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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.errorprone. **Name** : error_prone_annotations. **Version** : 2.47.0. + * **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.errorprone. **Name** : error_prone_check_api. **Version** : 2.36.0. * **Project URL:** [https://errorprone.info/error_prone_check_api](https://errorprone.info/error_prone_check_api) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13719,6 +13891,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://jcommander.org](https://jcommander.org) * **License:** [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 23.0.0. + * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains. **Name** : annotations. **Version** : 26.1.0. * **Project URL:** [https://github.com/JetBrains/java-annotations](https://github.com/JetBrains/java-annotations) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13875,6 +14051,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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-stdlib-jdk7. **Version** : 1.8.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk7. **Version** : 2.0.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13883,6 +14063,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 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-stdlib-jdk8. **Version** : 1.8.20. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib-jdk8. **Version** : 2.0.21. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13907,10 +14091,18 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-bom. **Version** : 1.7.3. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core. **Version** : 1.10.2. * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core. **Version** : 1.7.3. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core-jvm. **Version** : 1.10.2. * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13919,6 +14111,10 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-core-jvm. **Version** : 1.7.3. + * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) + * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-coroutines-jdk8. **Version** : 1.10.2. * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -13931,11 +14127,11 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using * **Project URL:** [https://github.com/Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.7.1. +1. **Group** : org.jetbrains.kotlinx. **Name** : kotlinx-datetime-jvm. **Version** : 0.8.0. * **Project URL:** [https://github.com/Kotlin/kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) * **License:** [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -14054,6 +14250,6 @@ This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Wed Jun 24 19:40:34 WEST 2026** using +This report was generated on **Mon Jun 29 18:10:45 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 fb1223a2..a401ee10 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 tool-base -2.0.0-SNAPSHOT.402 +2.0.0-SNAPSHOT.403 2015 @@ -176,13 +176,13 @@ all modules and does not describe the project structure per-subproject. io.spine spine-base - 2.0.0-SNAPSHOT.420 + 2.0.0-SNAPSHOT.421 compile io.spine spine-logging - 2.0.0-SNAPSHOT.417 + 2.0.0-SNAPSHOT.419 compile diff --git a/protobuf-setup-plugins/build.gradle.kts b/protobuf-setup-plugins/build.gradle.kts index 46e14eb4..b8c0465a 100644 --- a/protobuf-setup-plugins/build.gradle.kts +++ b/protobuf-setup-plugins/build.gradle.kts @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import io.spine.dependency.lib.Kotlin import io.spine.dependency.lib.Protobuf import io.spine.dependency.local.Base import io.spine.dependency.local.Logging @@ -31,6 +32,7 @@ import io.spine.gradle.isSnapshot import io.spine.gradle.publish.SpinePublishing import io.spine.gradle.report.license.LicenseReporter import io.spine.gradle.testing.enableTestKitCoverage +import org.gradle.plugin.devel.tasks.PluginUnderTestMetadata plugins { `uber-jar-module` @@ -111,6 +113,16 @@ dependencies { testImplementation(project(":plugin-testlib")) } +// Put the Kotlin Gradle plugin on the plugin-under-test classpath so the TestKit +// spec that applies it shares a classloader with this plugin, which uses the Kotlin +// Gradle plugin API (`KotlinSourceSet.generatedKotlin`). +val kotlinGradlePlugin = configurations.detachedConfiguration( + dependencies.create(Kotlin.GradlePlugin.lib) +) +tasks.withType().configureEach { + pluginClasspath.from(kotlinGradlePlugin) +} + publishing.publications.withType().configureEach { when (name) { "fatJar" -> { diff --git a/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt b/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt index 9307a516..1b0a94e6 100644 --- a/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt +++ b/protobuf-setup-plugins/src/main/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePlugin.kt @@ -44,6 +44,9 @@ import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.SourceDirectorySet import org.gradle.api.tasks.SourceSet import org.gradle.plugins.ide.idea.GenerateIdeaModule +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask /** @@ -152,8 +155,13 @@ private object GeneratedSubdir { * the tasks consuming the source sets (e.g., compilation, `sourcesJar`) run after * the generated code is copied. The dependency carried by the directories excluded * by this function is severed, so it must be re-established this way. + * + * Generated Kotlin sources are registered through the Kotlin Gradle plugin's dedicated + * `generatedKotlin` source directory set rather than the plain `kotlin` one, so that + * build tooling and IDEs can tell them apart from the hand-written code. */ @Internal +@OptIn(ExperimentalKotlinGradlePluginApi::class) context(_: GeneratedDirectoryContext) public fun GenerateProtoTask.configureSourceSetDirs() { val project = project @@ -189,25 +197,42 @@ public fun GenerateProtoTask.configureSourceSetDirs() { // Add the `grpc` directory unconditionally. // We may not have all the `protoc` plugins configured for the task at this time. // So, we cannot check if the `grpc` plugin is enabled. - // It is safe to add the directory anyway, because `srcDir()` does not require + // It is safe to add the directory anyway because `srcDir()` does not require // the directory to exist. java.srcDir(generatedSrc(GRPC)) } - fun SourceDirectorySet.setup() { - excludeFor(this@setup) - srcDir(generatedSrc(KOTLIN)) + fun KotlinSourceSet.setup() { + excludeFor(kotlin) + generatedKotlin.srcDir(generatedSrc(KOTLIN)) } if (project.hasKotlin()) { - val kotlinDirectorySet = sourceSet.findKotlinDirectorySet() - kotlinDirectorySet?.setup() - ?: project.afterEvaluate { - sourceSet.findKotlinDirectorySet()?.setup() - } + fun configureKotlin() { + project.findKotlinSourceSet(sourceSet.name)?.setup() + } + // The Kotlin plugin registers the `kotlin` source directory set as a + // source-set extension once it wires the source set. Gate on its presence + // to keep the original timing relative to the Protobuf plugin, then drive + // both the exclusion and the `generatedKotlin` registration from the matching + // `KotlinSourceSet`, whose `kotlin` set is that same extension. + if (sourceSet.findKotlinDirectorySet() != null) { + configureKotlin() + } else { + project.afterEvaluate { configureKotlin() } + } } } +/** + * Obtains the [KotlinSourceSet] with the given [name], or `null` if the project has no + * Kotlin extension, or it does not contain a source set with such a name. + */ +private fun Project.findKotlinSourceSet(name: String): KotlinSourceSet? = + extensions.findByType(KotlinBaseExtension::class.java) + ?.sourceSets + ?.findByName(name) + private fun File.residesIn(directory: File): Boolean = canonicalFile.startsWith(directory.absolutePath) diff --git a/protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePluginSpec.kt b/protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePluginSpec.kt index 1d92a8af..3dc15d24 100644 --- a/protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePluginSpec.kt +++ b/protobuf-setup-plugins/src/test/kotlin/io/spine/tools/protobuf/gradle/plugin/GeneratedSourcePluginSpec.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. @@ -28,6 +28,7 @@ package io.spine.tools.protobuf.gradle.plugin import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain +import io.kotest.matchers.string.shouldNotContain import io.spine.tools.gradle.testing.Gradle import io.spine.tools.gradle.testing.Gradle.BUILD_SUCCESSFUL import io.spine.tools.gradle.testing.runGradleBuild @@ -97,4 +98,92 @@ class GeneratedSourcePluginSpec : ProtobufPluginTest() { val sampleOuter = File(generatedJava, "sample/Sample.java") sampleOuter.exists() shouldBe true } + + @Test + fun `register generated Kotlin sources under the 'generatedKotlin' source set`() { + + // Settings file (empty is fine for single-project build). + Gradle.settingsFile.under(projectDir).writeText("") + + // Create a minimal proto file. The Kotlin `protoc` builtin (enabled by our + // plugin) generates a Kotlin DSL file for the message. + File(protoDir, "sample.proto").writeText( + """ + syntax = "proto3"; + package sample; + message Msg {} + """.trimIndent() + ) + + // Build file applying the Kotlin JVM, Protobuf, and our plugins. + // The `printKotlinSourceDirs` task reports which source set the generated + // Kotlin directory is registered under. + Gradle.buildFile.under(projectDir).writeText( + """ + import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi + import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet + + plugins { + // No version: resolved from the plugin-under-test classpath. + id("org.jetbrains.kotlin.jvm") + id("${ProtobufGradlePlugin.id}") version "${ProtobufGradlePlugin.version}" + id("${GeneratedSourcePlugin.id}") + } + + group = "$group" + version = "$version" + + repositories { + mavenCentral() + } + + protobuf { + protoc { artifact = "${ProtobufProtoc.dependency.artifact.coordinates}" } + } + + @OptIn(ExperimentalKotlinGradlePluginApi::class) + fun generatedKotlinSrcDirs(set: KotlinSourceSet) = + set.generatedKotlin.srcDirs + + val main = kotlin.sourceSets.getByName("main") + tasks.register("printKotlinSourceDirs") { + doLast { + println("KOTLIN_DIRS=" + main.kotlin.srcDirs) + println("GENERATED_KOTLIN_DIRS=" + generatedKotlinSrcDirs(main)) + } + } + """.trimIndent() + ) + + val generateProto = ProtobufTaskName.generateProto + val result = runGradleBuild( + projectDir, + listOf(generateProto.name(), "printKotlinSourceDirs"), + debug = false + ) + + result.task(generateProto.path())?.outcome shouldBe TaskOutcome.SUCCESS + result.output shouldContain BUILD_SUCCESSFUL + + // The copied directory is registered under `generatedKotlin`, and is absent + // from the plain `kotlin` source set. Paths are normalized to forward slashes + // so the substring check holds on Windows too. + val output = result.output + val generatedKotlinLine = output.lineSequence() + .first { it.startsWith("GENERATED_KOTLIN_DIRS=") } + .toUnix() + val kotlinLine = output.lineSequence() + .first { it.startsWith("KOTLIN_DIRS=") } + .toUnix() + val generatedKotlinSubpath = "generated/main/kotlin" + generatedKotlinLine shouldContain generatedKotlinSubpath + kotlinLine shouldNotContain generatedKotlinSubpath + + // The generated Kotlin sources are copied under `$projectDir/generated/main/kotlin`. + val generatedKotlinDir = File(projectDir, "generated/main/kotlin") + generatedKotlinDir.walkTopDown().any { it.extension == "kt" } shouldBe true + } } + +/** Replaces backslashes with forward slashes, normalizing a path across platforms. */ +private fun String.toUnix(): String = replace('\\', '/') diff --git a/version.gradle.kts b/version.gradle.kts index b82214e6..63087138 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.402") +val versionToPublish: String by extra("2.0.0-SNAPSHOT.403")