diff --git a/build.gradle.kts b/build.gradle.kts index 35ed706f2..f56b55242 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -183,20 +183,20 @@ private val INTEGRATION_TEST_TIMEOUT_MINUTES = 30L val publishedModules: Set = extensions.getByType().projectsToPublish() -val localPublish by tasks.registering { +val localPublish = tasks.register("localPublish") { val pubTasks = publishedModules.map { p -> p.tasks["publishToMavenLocal"] } dependsOn(pubTasks) } -val integrationTests by tasks.registering(RunBuild::class) { +val integrationTests = tasks.register("integrationTests") { directory = "$rootDir/tests" timeout.set(Duration.ofMinutes(INTEGRATION_TEST_TIMEOUT_MINUTES)) dependsOn(localPublish) subprojects.forEach { it.tasks.findByName("test")?.let { testTask -> - this@registering.dependsOn(testTask) + this@register.dependsOn(testTask) } } doLast { @@ -205,6 +205,6 @@ val integrationTests by tasks.registering(RunBuild::class) { } } -val check by tasks.existing { +tasks.named("check") { dependsOn(integrationTests) } 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 e3b4d0aa4..8dbffcdc4 100644 --- a/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt +++ b/buildSrc/src/main/kotlin/io/spine/dependency/local/Compiler.kt @@ -27,8 +27,6 @@ package io.spine.dependency.local import io.spine.dependency.Dependency -import io.spine.dependency.local.Compiler.DF_VERSION_ENV -import io.spine.dependency.local.Compiler.VERSION_ENV /** * Dependencies on the Spine Compiler modules. @@ -74,7 +72,7 @@ object Compiler : Dependency() { * The version of the Compiler dependencies. */ override val version: String - private const val fallbackVersion = "2.0.0-SNAPSHOT.057" + private const val fallbackVersion = "2.0.0-SNAPSHOT.059" /** * The distinct version of the Compiler used by other build tools. @@ -83,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.057" + private const val fallbackDfVersion = "2.0.0-SNAPSHOT.059" /** * The artifact for the Compiler Gradle plugin. diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt b/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt index 7e86ea94e..c84bb6e09 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/VersionGradleFile.kt @@ -33,14 +33,20 @@ 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): + * [keyForValue] and [valueForKey] resolve its `extra` properties. Each property is registered + * either with the current `extra.set("name", …)` call or the legacy `by extra(…)` property + * delegate that Gradle deprecated (the `bump-version` skill migrates the latter to the former); + * both spellings are recognized, so a file is read correctly whether or not it has migrated. + * The following value shapes are handled: * - * 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"`. + * 1. a literal: + * `extra.set("versionToPublish", "2.0.0-SNAPSHOT.182")`, or the legacy + * `val versionToPublish: String by extra("2.0.0-SNAPSHOT.182")`; + * 2. an alias to a plain `val` (or, in the legacy spelling, to another `extra`): + * `extra.set("versionToPublish", compilerVersion)` paired with + * `val compilerVersion = "2.0.0-SNAPSHOT.043"`, or the legacy + * `val versionToPublish by extra(compilerVersion)` paired with + * `val compilerVersion: String by extra("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`, @@ -56,10 +62,19 @@ internal object VersionGradleFile { */ const val NAME = "version.gradle.kts" + // Legacy `by extra(…)` property-delegate spellings (deprecated by Gradle). 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*\)""") + + // Current `extra.set("name", …)` spellings. + private val literalSet = + Regex("""extra\.set\(\s*"(\w+)"\s*,\s*"([^"]+)"\s*\)""") + private val aliasSet = + Regex("""extra\.set\(\s*"(\w+)"\s*,\s*([A-Za-z_]\w*)\s*\)""") + + // A plain `val name = "value"` that an alias may reference. private val plainAssignment = Regex("""val\s+(\w+)\s*(?::\s*String)?\s*=\s*"([^"]+)"""") @@ -68,12 +83,12 @@ internal object VersionGradleFile { * string value. */ private fun parse(content: String): Map { - val literals = literalExtra.findAll(content) + val literals = (literalExtra.findAll(content) + literalSet.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 -> + (aliasExtra.findAll(content) + aliasSet.findAll(content)).forEach { match -> val name = match.groupValues[1] val source = match.groupValues[2] if (name !in resolved) { diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/fs/LazyTempPath.kt b/buildSrc/src/main/kotlin/io/spine/gradle/fs/LazyTempPath.kt index 0344819f2..b31cd3087 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/fs/LazyTempPath.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/fs/LazyTempPath.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. @@ -41,11 +41,16 @@ import java.nio.file.WatchService * * After the first usage, the instances of this type delegate all calls to the internally * created instance of [Path] created with [createTempDirectory]. + * + * The directory is created under the [shared base directory][SpineTempDir], which is removed + * when the JVM — the Gradle daemon — shuts down. Build tasks delete their own directories + * eagerly as the primary cleanup; this shutdown removal is a safety net, so a directory does + * not outlive the daemon even when a build fails before its eager cleanup runs. */ @Suppress("TooManyFunctions") class LazyTempPath(private val prefix: String) : Path { - private val delegate: Path by lazy { createTempDirectory(prefix) } + private val delegate: Path by lazy { createTempDirectory(SpineTempDir.path, prefix) } override fun compareTo(other: Path): Int = delegate.compareTo(other) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/fs/SpineTempDir.kt b/buildSrc/src/main/kotlin/io/spine/gradle/fs/SpineTempDir.kt new file mode 100644 index 000000000..d6e856e01 --- /dev/null +++ b/buildSrc/src/main/kotlin/io/spine/gradle/fs/SpineTempDir.kt @@ -0,0 +1,92 @@ +/* + * 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.fs + +import java.nio.file.Files.createDirectories +import java.nio.file.Files.createTempDirectory +import java.nio.file.Path + +/** + * A per-JVM parent directory for the temporary directories created by the build. + * + * The directory is created [lazily][path] under a common, attributable namespace — + * `/io.spine.gradle.fs`, named after the package of [LazyTempPath] — so + * that leftover files are easy to attribute. Within that namespace, each JVM gets its own + * subdirectory named after the process id, so concurrent Gradle daemons never delete one + * another's temporary files. + * + * Upon creation, the per-JVM directory is scheduled for recursive removal when the JVM + * shuts down. This is a safety net should the explicit cleanup performed by the build + * tasks not run — for example, when a build fails before reaching it. The shared namespace + * directory itself is intentionally left in place: deleting it on shutdown could wipe + * directories still in use by another JVM running on the same machine. + * + * @see LazyTempPath + */ +internal object SpineTempDir { + + /** + * The per-JVM directory, created on the first access and removed on JVM shutdown. + */ + val path: Path by lazy { createPerJvmDir() } + + private fun createPerJvmDir(): Path { + val namespace = Path.of(systemTempDir(), LazyTempPath::class.java.packageName) + createDirectories(namespace) + // A per-JVM directory keeps concurrent Gradle daemons from deleting one another's + // files when their shutdown hooks fire. The PID makes a leftover directory easy + // to attribute; `createTempDirectory` adds a random suffix so that a reused PID + // still yields a unique directory. + val pid = ProcessHandle.current().pid() + val jvmDir = createTempDirectory(namespace, "$pid-") + deleteRecursivelyOnShutdown(jvmDir) + return jvmDir + } + + /** + * Obtains the value of the system property pointing to the temporary directory. + */ + private fun systemTempDir(): String = + checkNotNull(System.getProperty("java.io.tmpdir")) { + "The `java.io.tmpdir` system property is not set." + } + + /** + * Requests the recursive removal of the given [directory] when the JVM shuts down. + * + * @see Runtime.addShutdownHook + */ + private fun deleteRecursivelyOnShutdown(directory: Path) { + val runtime = Runtime.getRuntime() + runtime.addShutdownHook(Thread { + val deleted = directory.toFile().deleteRecursively() + if (!deleted) { + System.err.println("Unable to delete the temporary directory `$directory`.") + } + }) + } +} 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 64e46ef75..2a2a4c1c3 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 @@ -34,6 +34,7 @@ import kotlin.reflect.full.isSubclassOf import org.gradle.api.Project import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.result.ResolvedComponentResult import org.gradle.api.internal.artifacts.dependencies.AbstractExternalModuleDependency import org.gradle.kotlin.dsl.withGroovyBuilder @@ -54,6 +55,11 @@ import org.gradle.kotlin.dsl.withGroovyBuilder * * ``` * + * The version reported for each dependency is the one selected by Gradle's + * dependency resolution — the version actually placed on the classpath — rather + * than the version requested in the build script. This reflects `force(...)` + * directives, platform/BOM constraints, and conflict resolution. + * * When there are several versions of the same dependency, only the one with * the newest version is retained. If the retained version is used in several * configurations, the highest-ranking Maven scope is reported, e.g. `compile` @@ -107,38 +113,70 @@ private constructor( /** * Returns the [scoped dependencies][ScopedDependency] of a Gradle project. + * + * The version of each dependency is the one selected by dependency resolution + * for the project it comes from. See [resolvedVersions]. + */ +fun Project.dependencies(): SortedSet = + collectScopedDependencies { it.resolvedVersions() } + +/** + * Returns the [scoped dependencies][ScopedDependency] of a Gradle project, taking + * the version of each dependency from the given [resolvedVersions] map instead of + * resolving the project's own configurations. + * + * This overload exists for tests: a project created with `ProjectBuilder` cannot + * resolve its configurations against real repositories, so the resolved versions + * are supplied directly. The keys are the `"group:name"` of the modules. */ -fun Project.dependencies(): SortedSet { +internal fun Project.dependencies( + resolvedVersions: Map +): SortedSet = + collectScopedDependencies { resolvedVersions } + +/** + * Collects the [scoped dependencies][ScopedDependency] of this project and its + * subprojects, deduplicates them, and returns them in the conventional Maven order. + * + * The version of each dependency is taken from the map returned by the supplied + * `resolvedVersionsOf` function for the project the dependency comes from. + */ +private fun Project.collectScopedDependencies( + resolvedVersionsOf: (Project) -> Map +): SortedSet { val dependencies = mutableSetOf() - dependencies.addAll(this.depsFromAllConfigurations()) + dependencies.addAll(depsFromAllConfigurations(resolvedVersionsOf(this))) - this.subprojects.forEach { subproject -> - val subprojectDeps = subproject.depsFromAllConfigurations() + subprojects.forEach { subproject -> + val subprojectDeps = subproject.depsFromAllConfigurations(resolvedVersionsOf(subproject)) dependencies.addAll(subprojectDeps) } - val result = deduplicate(dependencies) + return deduplicate(dependencies) .map { it.scoped } .toSortedSet() - return result } /** * Returns the external dependencies of the project from all the project configurations. + * + * The version of each returned dependency is taken from [resolvedVersions] by its + * `"group:name"` key, falling back to the declared version when the module is on no + * resolvable configuration — for example, a version managed by a BOM, which carries + * no explicit version of its own. */ -private fun Project.depsFromAllConfigurations(): Set { +private fun Project.depsFromAllConfigurations( + resolvedVersions: Map +): Set { val result = mutableSetOf() - this.configurations.forEach { configuration -> + configurations.forEach { configuration -> configuration.dependencies .filter { it.isExternal() } .forEach { dependency -> - val forcedVersion = configuration.forcedVersionOf(dependency) + val version = resolvedVersions[moduleKey(dependency.group, dependency.name)] + ?: dependency.version val moduleDependency = - if (forcedVersion != null) { - ModuleDependency(project, configuration, dependency, forcedVersion) - } else { - ModuleDependency(project, configuration, dependency) - } + ModuleDependency(this, configuration, dependency, factualVersion = version) result.add(moduleDependency) } } @@ -146,20 +184,55 @@ private fun Project.depsFromAllConfigurations(): Set { } /** - * Searches for a forced version of given [dependency] in this [Configuration]. + * Returns the versions selected by dependency resolution for this project, keyed + * by the `"group:name"` of each module. + * + * The declared version of a dependency is what the build script *requested*, which + * may differ from what the build *uses*: a `force(...)`, a platform/BOM constraint, + * or Gradle's conflict resolution can all select another version. Reading the + * resolution result captures the selected version, so the report describes the + * dependencies actually on the classpath rather than the requested ones. * - * Returns `null`, if it wasn't forced. + * Only resolvable configurations contribute. When a module resolves to different + * versions across configurations, the newest one (by [VersionComparator]) is kept, + * matching the deduplication applied afterwards. A configuration that fails to + * resolve in isolation is skipped and logged, so the report never breaks the build. */ -private fun Configuration.forcedVersionOf(dependency: Dependency): String? { - val forcedModules = resolutionStrategy.forcedModules - val maybeForced = forcedModules.firstOrNull { - it.group == dependency.group - && it.name == dependency.name - && it.version != null - } - return maybeForced?.version +private fun Project.resolvedVersions(): Map { + // Resolving an individual configuration may fail for reasons unrelated to the + // report — missing repositories for a niche configuration, an unsatisfiable + // constraint, and the like. Such a configuration contributes no versions. + @Suppress("TooGenericExceptionCaught") // Any resolution failure is non-fatal here. + fun componentsOf(configuration: Configuration): Set = + try { + configuration.incoming.resolutionResult.allComponents + } catch (e: Exception) { + logger.info( + "Skipping configuration `${configuration.name}` " + + "while collecting resolved dependency versions.", + e + ) + emptySet() + } + + return configurations + .filter { it.isCanBeResolved } + .flatMap { componentsOf(it) } + .mapNotNull { it.moduleVersion } + .groupBy { moduleKey(it.group, it.name) } + .mapValues { (_, versions) -> versions.maxOfWith(VersionComparator) { it.version } } } +/** + * Builds the `"group:name"` key under which a module's resolved version is recorded + * and looked up. + * + * Forming the key in one place keeps the lookup in [depsFromAllConfigurations] + * consistent with what [resolvedVersions] records and with the grouping done by + * [deduplicate]. + */ +private fun moduleKey(group: String?, name: String): String = "$group:$name" + /** * Tells whether the dependency is an external module dependency. */ @@ -193,7 +266,7 @@ private fun Dependency.isExternal(): Boolean { * The rejected duplicates are logged. */ private fun Project.deduplicate(dependencies: Set): List { - val groups = dependencies.groupBy { it.run { "$group:$name" } } + val groups = dependencies.groupBy { moduleKey(it.group, it.name) } logDuplicates(groups.mapValues { (_, deps) -> deps.distinctBy { it.gav } }) diff --git a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ProjectMetadata.kt b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ProjectMetadata.kt index ffb89a263..66e3400e2 100644 --- a/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ProjectMetadata.kt +++ b/buildSrc/src/main/kotlin/io/spine/gradle/report/pom/ProjectMetadata.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,9 +30,7 @@ import groovy.xml.MarkupBuilder import java.io.StringWriter import kotlin.reflect.KProperty import org.gradle.api.Project -import org.gradle.kotlin.dsl.PropertyDelegate import org.gradle.kotlin.dsl.extra -import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.withGroovyBuilder /** @@ -90,10 +88,10 @@ private fun Project.nonEmptyValue(prop: Any): NonEmptyValue { private class NonEmptyValue( private val defaultValue: String, private val project: Project -) : PropertyDelegate { +) { @Suppress("UNCHECKED_CAST") - override fun getValue(receiver: Any?, property: KProperty<*>): T { + operator fun getValue(receiver: Any?, property: KProperty<*>): T { if (defaultValue.isNotEmpty()) { return defaultValue as T } diff --git a/buildSrc/src/main/kotlin/jacoco-kmm-jvm.gradle.kts b/buildSrc/src/main/kotlin/jacoco-kmm-jvm.gradle.kts deleted file mode 100644 index 7334ef97f..000000000 --- a/buildSrc/src/main/kotlin/jacoco-kmm-jvm.gradle.kts +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - */ - -import java.io.File -import org.gradle.kotlin.dsl.getValue -import org.gradle.kotlin.dsl.getting -import org.gradle.kotlin.dsl.jacoco -import org.gradle.testing.jacoco.tasks.JacocoReport - -// DEPRECATED: this script plugin distributes vanilla JaCoCo. -// New code should apply `kmp-module`, which configures Kover via -// `useJacoco(version = Jacoco.version)` and writes JaCoCo-format XML at -// `build/reports/kover/report.xml`. (Same task and path as Kotlin-JVM — -// `kmp-module` configures only Kover's `total` report, so no -// `koverXmlReport` task is generated.) The `raise-coverage` skill -// migrates existing consumers automatically. Kept so older consumer repos -// continue to build; will be removed in a future release. -// See: .agents/skills/raise-coverage/references/migrate-to-kover.md - -plugins { - jacoco -} - -logger.warn( - "'jacoco-kmm-jvm' is deprecated; use 'kmp-module' which applies Kover. " + - "See .agents/skills/raise-coverage/references/migrate-to-kover.md." -) - -/** - * Configures [JacocoReport] task to run in a Kotlin KMM project for `commonMain` and `jvmMain` - * source sets. - * - * This script plugin must be applied using the following construct at the end of - * a `build.gradle.kts` file of a module: - * - * ```kotlin - * apply(plugin="jacoco-kmm-jvm") - * ``` - * Please do not apply this script plugin in the `plugins {}` block because `jacocoTestReport` - * task is not yet available at this stage. - */ -@Suppress("unused") -private val about = "" - -/** - * Configure the Jacoco task with custom input a KMM project - * to which this convention plugin is applied. - */ -@Suppress("unused") -val jacocoTestReport: JacocoReport by tasks.getting(JacocoReport::class) { - val buildDir = project.layout.buildDirectory.get().asFile.absolutePath - val classFiles = File("${buildDir}/classes/kotlin/jvm/") - .walkBottomUp() - .toSet() - classDirectories.setFrom(classFiles) - - val coverageSourceDirs = arrayOf( - "src/commonMain", - "src/jvmMain" - ) - sourceDirectories.setFrom(files(coverageSourceDirs)) - - executionData.setFrom(files("${buildDir}/jacoco/jvmTest.exec")) -} diff --git a/buildSrc/src/main/kotlin/jacoco-kotlin-jvm.gradle.kts b/buildSrc/src/main/kotlin/jacoco-kotlin-jvm.gradle.kts deleted file mode 100644 index 185c9cdfd..000000000 --- a/buildSrc/src/main/kotlin/jacoco-kotlin-jvm.gradle.kts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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. - */ - -import io.spine.gradle.buildDirectory - -// DEPRECATED: this script plugin distributes vanilla JaCoCo. -// New code should apply `jvm-module`, which configures Kover via -// `useJacoco(version = Jacoco.version)` and writes JaCoCo-format XML at -// `build/reports/kover/report.xml`. The `raise-coverage` skill migrates -// existing consumers automatically. Kept so older consumer repos continue to -// build; will be removed in a future release. -// See: .agents/skills/raise-coverage/references/migrate-to-kover.md - -plugins { - jacoco -} - -logger.warn( - "'jacoco-kotlin-jvm' is deprecated; use 'jvm-module' which applies Kover. " + - "See .agents/skills/raise-coverage/references/migrate-to-kover.md." -) - -/** - * Configures [JacocoReport] task to run in a Kotlin Multiplatform project for - * `commonMain` and `jvmMain` source sets. - * - * This script plugin must be applied using the following construct at the end of - * a `build.gradle.kts` file of a module: - * - * ```kotlin - * apply(plugin="jacoco-kotlin-jvm") - * ``` - * Please do not apply this script plugin in the `plugins {}` block because `jacocoTestReport` - * task is not yet available at this stage. - */ -@Suppress("unused") -private val about = "" - -/** - * Configure Jacoco task with custom input from this Kotlin Multiplatform project. - */ -@Suppress("unused") -val jacocoTestReport: JacocoReport by tasks.getting(JacocoReport::class) { - - val classFiles = File("$buildDirectory/classes/kotlin/jvm/") - .walkBottomUp() - .toSet() - classDirectories.setFrom(classFiles) - - val coverageSourceDirs = arrayOf( - "src/commonMain", - "src/jvmMain" - ) - sourceDirectories.setFrom(files(coverageSourceDirs)) - - executionData.setFrom(files("$buildDirectory/jacoco/jvmTest.exec")) -} diff --git a/buildSrc/src/main/kotlin/jvm-module.gradle.kts b/buildSrc/src/main/kotlin/jvm-module.gradle.kts index 8e777c6ac..1438116b7 100644 --- a/buildSrc/src/main/kotlin/jvm-module.gradle.kts +++ b/buildSrc/src/main/kotlin/jvm-module.gradle.kts @@ -154,7 +154,7 @@ fun Module.forceConfigurations() { fun Module.setTaskDependencies(generatedDir: String) { tasks { - val cleanGenerated by registering(Delete::class) { + val cleanGenerated = register("cleanGenerated") { group = SpineTaskGroup.name description = "Deletes the directory with generated sources" delete(generatedDir) diff --git a/buildSrc/src/main/kotlin/kmp-module.gradle.kts b/buildSrc/src/main/kotlin/kmp-module.gradle.kts index 636a84d22..4db37f108 100644 --- a/buildSrc/src/main/kotlin/kmp-module.gradle.kts +++ b/buildSrc/src/main/kotlin/kmp-module.gradle.kts @@ -38,6 +38,7 @@ import io.spine.gradle.javac.configureJavac import io.spine.gradle.kotlin.setFreeCompilerArgs import io.spine.gradle.publish.IncrementGuard import io.spine.gradle.report.license.LicenseReporter +import io.spine.gradle.testing.configureLogging /** * Configures this [Project] as a Kotlin Multiplatform module. @@ -126,9 +127,8 @@ kotlin { // Dependencies are specified per-target. // Please note, common sources are implicitly available in all targets. - @Suppress("unused") // source set `val`s are used implicitly. sourceSets { - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) @@ -136,7 +136,7 @@ kotlin { implementation(Kotest.frameworkEngine) } } - val jvmTest by getting { + getByName("jvmTest") { dependencies { implementation(dependencies.enforcedPlatform(JUnit.bom)) implementation(TestLib.lib) @@ -162,11 +162,22 @@ java { * * Also, Kotlin and Java share the same test executor (JUnit), so tests * configuration is for both. + * + * The `jvmTest` task mirrors the setup made by `module-testing` for + * the `test` task of a `jvm-module` (`module-testing` itself cannot be + * applied here because it brings `java-library`, which conflicts with + * the Kotlin Multiplatform plugin). Unlike `module-testing`, no engine + * filter is imposed: `jvmTest` dependencies include the Kotest runner, + * which is a JUnit Platform engine of its own. */ tasks { withType().configureEach { configureJavac() } + named("jvmTest") { + useJUnitPlatform() + configureLogging() + } } /** diff --git a/buildSrc/src/main/kotlin/module.gradle.kts b/buildSrc/src/main/kotlin/module.gradle.kts index dcfef5cf8..3b68ba1ca 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. @@ -170,7 +170,7 @@ fun Module.forceConfigurations() { fun Module.setTaskDependencies(generatedDir: String) { tasks { - val cleanGenerated by registering(Delete::class) { + val cleanGenerated = register("cleanGenerated") { delete(generatedDir) } clean.configure { diff --git a/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts b/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts index 0cace2ebe..e59e30ef8 100644 --- a/buildSrc/src/main/kotlin/uber-jar-module.gradle.kts +++ b/buildSrc/src/main/kotlin/uber-jar-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. @@ -70,11 +70,8 @@ publishing { } } -/** - * Declare dependency explicitly to address the Gradle error. - */ -@Suppress("unused") -val publishFatJarPublicationToMavenLocal: Task by tasks.getting { +// Declare dependency explicitly to address the Gradle error. +tasks.getByName("publishFatJarPublicationToMavenLocal") { dependsOn(tasks.shadowJar) } diff --git a/buildSrc/src/main/kotlin/write-manifest.gradle.kts b/buildSrc/src/main/kotlin/write-manifest.gradle.kts index 49130c0c4..2c49daa7c 100644 --- a/buildSrc/src/main/kotlin/write-manifest.gradle.kts +++ b/buildSrc/src/main/kotlin/write-manifest.gradle.kts @@ -104,7 +104,7 @@ val manifestAttributes = mapOf( * when running tests. We cannot depend on the `Jar` from `resources` because it would * form a circular dependency. */ -val exposeManifestForTests by tasks.registering { +val exposeManifestForTests = tasks.register("exposeManifestForTests") { group = SpineTaskGroup.name description = "Writes a `MANIFEST.MF` to `resources/main` so that it is visible to tests" diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt index e76febe21..dd5e2798e 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/VersionGradleFileSpec.kt @@ -64,6 +64,28 @@ internal class VersionGradleFileSpec { VersionGradleFile.valueForKey(content, "versionToPublish") shouldBe "2.0.0-SNAPSHOT.043" } + @Test + fun `declared as a literal via 'extra set'`() { + val content = """ + extra.set("versionToPublish", "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 via 'extra set'`() { + val content = """ + val compilerVersion = "2.0.0-SNAPSHOT.043" + extra.set("compilerVersion", compilerVersion) + extra.set("versionToPublish", compilerVersion) + """.trimIndent() + + VersionGradleFile.valueForKey(content, "versionToPublish") shouldBe "2.0.0-SNAPSHOT.043" + VersionGradleFile.valueForKey(content, "compilerVersion") shouldBe "2.0.0-SNAPSHOT.043" + } + @Test fun `identified by the resolved project version, not a hard-coded name`() { val content = """ diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/fs/LazyTempPathSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/fs/LazyTempPathSpec.kt new file mode 100644 index 000000000..260e852fe --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/fs/LazyTempPathSpec.kt @@ -0,0 +1,69 @@ +/* + * 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.fs + +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`LazyTempPath` should") +class LazyTempPathSpec { + + @Test + fun `create the directory on the first use`() { + val directory = LazyTempPath("created").toFile() + + directory.exists() shouldBe true + directory.isDirectory shouldBe true + } + + @Test + fun `create the directory under the system temporary directory`() { + val path = LazyTempPath("under-tmp").toString() + + path shouldContain systemTempDir() + } + + @Test + fun `create the directory under a folder named after its package`() { + val path = LazyTempPath("under-base").toString() + + path shouldContain LazyTempPath::class.java.packageName + } + + @Test + fun `place all instances under the same base directory`() { + val first = LazyTempPath("first").toFile() + val second = LazyTempPath("second").toFile() + + first.parentFile shouldBe second.parentFile + first.parentFile.toString() shouldBe SpineTempDir.path.toString() + } +} + +private fun systemTempDir(): String = System.getProperty("java.io.tmpdir") diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/fs/SpineTempDirSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/fs/SpineTempDirSpec.kt new file mode 100644 index 000000000..8bf42500a --- /dev/null +++ b/buildSrc/src/test/kotlin/io/spine/gradle/fs/SpineTempDirSpec.kt @@ -0,0 +1,54 @@ +/* + * 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.fs + +import io.kotest.matchers.shouldBe +import java.nio.file.Path +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@DisplayName("`SpineTempDir` should") +class SpineTempDirSpec { + + @Test + fun `place its per-JVM directory under the package-named namespace`() { + val namespace = Path.of( + System.getProperty("java.io.tmpdir"), + LazyTempPath::class.java.packageName + ) + + SpineTempDir.path.parent shouldBe namespace + } + + @Test + fun `create the directory on access`() { + val directory = SpineTempDir.path.toFile() + + directory.exists() shouldBe true + directory.isDirectory shouldBe true + } +} diff --git a/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt index 0c4b23355..baec7877d 100644 --- a/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt +++ b/buildSrc/src/test/kotlin/io/spine/gradle/report/pom/DependencyWriterSpec.kt @@ -31,12 +31,16 @@ import io.kotest.matchers.ints.shouldBeLessThan import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import io.kotest.matchers.string.shouldNotContain +import java.io.File import java.io.StringWriter +import org.gradle.api.Action import org.gradle.api.Project +import org.gradle.api.artifacts.repositories.MavenArtifactRepository import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir @DisplayName("`DependencyWriter` should") internal class DependencyWriterSpec { @@ -246,6 +250,112 @@ internal class DependencyWriterSpec { } } + @Nested inner class + `report the version selected by dependency resolution` { + + /** + * A `force(...)` pins an artifact to a version that is *older* than one of + * the declared ones. The report must show the resolved version — the one + * actually on the classpath — and not the newest of the declared ones, + * which the deduplication would otherwise pick. + */ + @Test + fun `preferring it over a newer declared version`() { + val older = "$VALIDATION_RUNTIME:2.0.0-SNAPSHOT.40" + val newer = "$VALIDATION_RUNTIME:2.0.0-SNAPSHOT.61" + subproject("a-text").declare("implementation", newer) + subproject("b-text").declare("implementation", older) + + val resolved = mapOf(VALIDATION_RUNTIME to "2.0.0-SNAPSHOT.40") + val dependency = rootProject.dependencies(resolved).single() + + dependency.dependency().version shouldBe "2.0.0-SNAPSHOT.40" + } + + /** + * Two versions of the same artifact declared in a single module and + * configuration — the case that used to log a spurious "several versions" + * warning — collapse to the single resolved version. + */ + @Test + fun `collapsing several declarations within one configuration`() { + val text = subproject("text") + text.declare("implementation", "$VALIDATION_RUNTIME:2.0.0-SNAPSHOT.61") + text.declare("implementation", "$VALIDATION_RUNTIME:2.0.0-SNAPSHOT.40") + + val resolved = mapOf(VALIDATION_RUNTIME to "2.0.0-SNAPSHOT.61") + val dependency = rootProject.dependencies(resolved).single() + + dependency.dependency().version shouldBe "2.0.0-SNAPSHOT.61" + } + + @Test + fun `falling back to the declared version when it is not resolved`() { + subproject("lib").declare("api", SPINE_BASE) + + val dependency = rootProject.dependencies(emptyMap()).single() + + dependency.dependency().version shouldBe "2.0.0" + } + } + + @Nested inner class + `read the version from a resolved configuration` { + + /** + * Drives the real (non-injected) `dependencies()` entry point against an + * actually resolved configuration. A module is declared at one version but + * `force`d to an older one; the report must show the forced, i.e. resolved, + * version. The forcing is observable only through resolution, so the module + * is resolved from a local repository of metadata-only POMs. + */ + @Test + fun `honoring a forced version over the declared one`(@TempDir repoDir: File) { + val group = "io.spine.validation" + val name = "spine-validation-java-runtime" + publishPom(repoDir, group, name, "1.0.40") + publishPom(repoDir, group, name, "1.0.61") + + val text = subproject("text") + text.addMavenRepository(repoDir) + val api = text.configurations.create("api") + api.isCanBeResolved = true + api.resolutionStrategy.force("$group:$name:1.0.40") + text.dependencies.add("api", "$group:$name:1.0.61") + + val dependency = rootProject.dependencies().single() + + dependency.dependency().version shouldBe "1.0.40" + } + + /** Writes a metadata-only Maven POM for the module under [repoDir]. */ + private fun publishPom(repoDir: File, group: String, name: String, version: String) { + val dir = File(repoDir, "${group.replace('.', '/')}/$name/$version") + dir.mkdirs() + File(dir, "$name-$version.pom").writeText( + """ + + 4.0.0 + $group + $name + $version + + """.trimIndent() + ) + } + + private fun Project.addMavenRepository(dir: File) { + // The `org.gradle.kotlin.dsl` `maven { }` accessors are not on the + // `buildSrc` test compile classpath, so the core `Action` overload is + // used directly rather than the DSL lambda. + repositories.maven(object : Action { + override fun execute(repository: MavenArtifactRepository) { + repository.setUrl(dir.toURI()) + } + }) + } + } + @Test fun `omit the scope of a dependency coming only from an unknown configuration`() { subproject("lib").declare("spineCompiler", SPINE_BASE) @@ -308,5 +418,8 @@ internal class DependencyWriterSpec { private companion object { const val SPINE_BASE = "io.spine:spine-base:2.0.0" const val SPINE_BASE_NEWER = "io.spine:spine-base:2.0.1" + + /** The `"group:name"` of the validation runtime artifact, without a version. */ + const val VALIDATION_RUNTIME = "io.spine.validation:spine-validation-java-runtime" } } diff --git a/config b/config index 3f13608b3..c2aae6e74 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit 3f13608b3bb1a8bc736fbb748b95ec3dc11843a2 +Subproject commit c2aae6e74662ddbe60e3e8695cc6a1b8b104f0a3 diff --git a/docs/dependencies/dependencies.md b/docs/dependencies/dependencies.md index dfd8cd125..ff0cd9f6a 100644 --- a/docs/dependencies/dependencies.md +++ b/docs/dependencies/dependencies.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine.tools:time-gradle-plugin:2.0.0-SNAPSHOT.243` +# Dependencies of `io.spine.tools:time-gradle-plugin:2.0.0-SNAPSHOT.244` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.0. @@ -1063,14 +1063,14 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using +This report was generated on **Thu Jul 02 19:01:06 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:time-testlib:2.0.0-SNAPSHOT.243` +# Dependencies of `io.spine.tools:time-testlib:2.0.0-SNAPSHOT.244` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -1881,14 +1881,14 @@ This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using +This report was generated on **Thu Jul 02 19:01:06 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-time:2.0.0-SNAPSHOT.243` +# Dependencies of `io.spine:spine-time:2.0.0-SNAPSHOT.244` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -2857,14 +2857,14 @@ This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using +This report was generated on **Thu Jul 02 19:01:06 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-time-java:2.0.0-SNAPSHOT.243` +# Dependencies of `io.spine:spine-time-java:2.0.0-SNAPSHOT.244` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -3675,14 +3675,14 @@ This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using +This report was generated on **Thu Jul 02 19:01:06 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-time-kotlin:2.0.0-SNAPSHOT.243` +# Dependencies of `io.spine:spine-time-kotlin:2.0.0-SNAPSHOT.244` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -4501,14 +4501,14 @@ This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using +This report was generated on **Thu Jul 02 19:01:06 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:time-validation:2.0.0-SNAPSHOT.243` +# Dependencies of `io.spine.tools:time-validation:2.0.0-SNAPSHOT.244` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.0. @@ -5638,14 +5638,14 @@ This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using +This report was generated on **Thu Jul 02 19:01:06 WEST 2026** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-validation-tests:2.0.0-SNAPSHOT.243` +# Dependencies of `io.spine:spine-validation-tests:2.0.0-SNAPSHOT.244` ## Runtime 1. **Group** : com.fasterxml.jackson. **Name** : jackson-bom. **Version** : 2.22.0. @@ -6735,6 +6735,6 @@ This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Tue Jun 30 02:12:18 WEST 2026** using +This report was generated on **Thu Jul 02 19:01:06 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 2e737acf9..a209ce38a 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 time -2.0.0-SNAPSHOT.243 +2.0.0-SNAPSHOT.244 2015 @@ -68,13 +68,13 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-gradle-api - 2.0.0-SNAPSHOT.057 + 2.0.0-SNAPSHOT.059 compile io.spine.tools compiler-jvm - 2.0.0-SNAPSHOT.057 + 2.0.0-SNAPSHOT.059 compile @@ -134,7 +134,7 @@ all modules and does not describe the project structure per-subproject. com.google.errorprone error_prone_annotations - 2.36.0 + 2.47.0 provided @@ -170,7 +170,7 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-testlib - 2.0.0-SNAPSHOT.057 + 2.0.0-SNAPSHOT.059 test @@ -242,12 +242,12 @@ all modules and does not describe the project structure per-subproject. io.spine.tools compiler-cli-all - 2.0.0-SNAPSHOT.057 + 2.0.0-SNAPSHOT.059 io.spine.tools compiler-protoc-plugin - 2.0.0-SNAPSHOT.057 + 2.0.0-SNAPSHOT.059 io.spine.tools diff --git a/gradle-plugin/build.gradle.kts b/gradle-plugin/build.gradle.kts index 82ed55f30..ade95b36b 100644 --- a/gradle-plugin/build.gradle.kts +++ b/gradle-plugin/build.gradle.kts @@ -41,7 +41,7 @@ group = "io.spine.tools" val moduleArtifactId = "time-gradle-plugin" -val versionToPublish: String by extra +val versionToPublish = extra["versionToPublish"] as String artifactMeta { artifactId.set(moduleArtifactId) @@ -101,7 +101,7 @@ afterEvaluate { // The above `publishing` block is executed after `ArtifactMetaPlugin` attempts to add // the dependency in the `afterEvaluate` block the plugin adds itself. // Therefore, we have to arrange the dependency manually below. - val sourcesJar by tasks.getting(Jar::class) - val writeArtifactMeta by tasks.getting + val sourcesJar = tasks.getByName("sourcesJar") + val writeArtifactMeta = tasks.getByName("writeArtifactMeta") sourcesJar.dependsOn(writeArtifactMeta) } diff --git a/version.gradle.kts b/version.gradle.kts index f494141ff..a60fba175 100644 --- a/version.gradle.kts +++ b/version.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. @@ -27,4 +27,4 @@ /** * The version of this library for publishing. */ -val versionToPublish by extra("2.0.0-SNAPSHOT.243") +extra.set("versionToPublish", "2.0.0-SNAPSHOT.244")