Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ plugins {
val gradlePluginModule = "gradle-plugin"

spinePublishing {
artifactPrefix = "spine-"
toolArtifactPrefix = "time-"
modules = productionModules.map { it.name }.toSet() - gradlePluginModule
modulesWithCustomPublishing = setOf(gradlePluginModule)
destinations = with(PublishingRepos) {
Expand Down
23 changes: 23 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,20 @@ val koverVersion = "0.9.1"
*/
val shadowVersion = "9.2.2"

/**
* The version of JUnit used to test the build scripts.
*
* @see [io.spine.dependency.test.JUnit]
*/
val junitVersion = "6.0.3"

/**
* The version of Kotest used to test the build scripts.
*
* @see [io.spine.dependency.test.Kotest]
*/
val kotestVersion = "6.1.10"

configurations.all {
resolutionStrategy {
force(
Expand Down Expand Up @@ -192,6 +206,15 @@ dependencies {
).forEach {
implementation(it)
}

testImplementation(platform("org.junit:junit-bom:$junitVersion"))
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("io.kotest:kotest-assertions-core:$kotestVersion")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

tasks.test {
useJUnitPlatform()
}

dependOnBuildSrcJar()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ object CoreJvmCompiler {
/**
* The version used to in the build classpath.
*/
const val dogfoodingVersion = "2.0.0-SNAPSHOT.055"
const val dogfoodingVersion = "2.0.0-SNAPSHOT.058"

/**
* The version to be used for integration tests.
*/
const val version = "2.0.0-SNAPSHOT.055"
const val version = "2.0.0-SNAPSHOT.058"

/**
* The ID of the Gradle plugin.
Expand Down
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/io/spine/dependency/local/Time.kt
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -40,7 +40,7 @@ import io.spine.dependency.Dependency
)
object Time : Dependency() {
override val group = Spine.group
override val version = "2.0.0-SNAPSHOT.232"
override val version = "2.0.0-SNAPSHOT.234"
private const val infix = "spine-time"

fun lib(version: String): String = "$group:$infix:$version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.375"
const val dogfoodingVersion = "2.0.0-SNAPSHOT.375"
const val version = "2.0.0-SNAPSHOT.376"
const val dogfoodingVersion = "2.0.0-SNAPSHOT.376"

const val lib = "$group:tool-base:$version"
const val classicCodegen = "$group:classic-codegen:$version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ package io.spine.dependency.test
*/
@Suppress("unused", "ConstPropertyName")
object Kotest {
const val version = "6.0.4"
const val version = "6.1.10"
const val group = "io.kotest"
const val gradlePluginId = "io.kotest"
const val assertions = "$group:kotest-assertions-core:$version"
Expand Down
125 changes: 125 additions & 0 deletions buildSrc/src/main/kotlin/io/spine/gradle/docs/UpdatePluginVersion.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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.docs

import java.io.File
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction

/**
* Updates the version of a Gradle plugin in `build.gradle.kts` files.
*
* The task searches for plugin declarations in the format
* `id("plugin-id") version "version-number"` and replaces
* the version number with the one found in the version script file.
*
* @property directory
* The directory to scan recursively for `build.gradle.kts` files.
* @property version
* The version number to set for the plugin.
* @property pluginId
* The ID of the plugin whose version should be updated.
* @property kotlinVersion
* Optional. If set, updates the version of the Kotlin plugin declared with
* `kotlin("…") version "…"` syntax in the `plugins` block.
* This option works in combination with the [version] and [pluginId] properties.
*/
abstract class UpdatePluginVersion : DefaultTask() {

@get:InputDirectory
abstract val directory: DirectoryProperty

@get:Input
abstract val version: Property<String>

@get:Input
abstract val pluginId: Property<String>

@get:Input
@get:Optional
abstract val kotlinVersion: Property<String>

/**
* Updates plugin versions in build files within the path in the [directory].
*/
@TaskAction
fun update() {
val rootDir = directory.get().asFile

val kotlinVersionSet = kotlinVersion.isPresent
val kotlinVer = kotlinVersion.orNull
val id = pluginId.get()
val ver = version.get()

rootDir.walkTopDown()
.filter { it.name == "build.gradle.kts" }
.forEach { file ->
if (kotlinVersionSet && kotlinVer != null) {
updateKotlinPluginVersion(file, kotlinVer)
}
updatePluginVersion(file, id, ver)
}
}

@Suppress("MemberNameEqualsClassName")
private fun updatePluginVersion(file: File, id: String, version: String) {
val content = file.readText()
// Regex to match: id("plugin-id") version "version-number"
val regex = """id\("$id"\)\s+version\s+"([^"]+)"""".toRegex()

if (regex.containsMatchIn(content)) {
val updatedContent = regex.replace(content) {
"id(\"$id\") version \"$version\""
}
if (content != updatedContent) {
file.writeText(updatedContent)
logger.info("Updated version of '$id' in `${file.absolutePath}`.")
}
}
}

private fun updateKotlinPluginVersion(file: File, kotlinVersion: String) {
val content = file.readText()
// Regex to match Kotlin plugin declarations like: kotlin("jvm") version "1.9.0"
val regex = """kotlin\("([^"]+)"\)\s+version\s+"([^"]+)"""".toRegex()
if (regex.containsMatchIn(content)) {
val updatedContent = regex.replace(content) { matchResult ->
val plugin = matchResult.groupValues[1]
"kotlin(\"$plugin\") version \"$kotlinVersion\""
}
if (content != updatedContent) {
file.writeText(updatedContent)
logger.info("Updated Kotlin plugin version in `${file.absolutePath}`.")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -29,6 +29,7 @@
package io.spine.gradle.publish

import io.spine.gradle.repo.Repository
import java.util.Locale
import org.gradle.api.Project
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
import org.gradle.kotlin.dsl.apply
Expand Down Expand Up @@ -145,16 +146,18 @@ import org.gradle.kotlin.dsl.findByType
* @see [artifacts]
* @see SpinePublishing
*/
fun Project.spinePublishing(block: SpinePublishing.() -> Unit) {
fun Project.spinePublishing(block: SpinePublishing.() -> Unit): SpinePublishing {
apply<MavenPublishPlugin>()
val name = SpinePublishing::class.java.simpleName
.replaceFirstChar { it.lowercase(Locale.getDefault()) }
val extension = with(extensions) {
findByType<SpinePublishing>() ?: create(name, project)
}
extension.run {
block()
configured()
}
return extension
}

/**
Expand Down Expand Up @@ -182,6 +185,12 @@ open class SpinePublishing(private val project: Project) {
* The default prefix added before a module name when publishing artifacts.
*/
const val DEFAULT_PREFIX = "spine-"

/**
* The reserved value that means that no prefix should be added
* to a tool module's artifact ID.
*/
const val NONE_PREFIX = "NONE"
}

private val testJar = TestJar()
Expand Down Expand Up @@ -250,10 +259,23 @@ open class SpinePublishing(private val project: Project) {
lateinit var destinations: Set<Repository>

/**
* A prefix to be added before the name of each artifact.
* A prefix to be added before the name of each artifact, if it does not belong
* to the Maven group `"io.spine.tools"`.
*
* @see toolArtifactPrefix
*/
var artifactPrefix: String = DEFAULT_PREFIX

/**
* A prefix to be added before a module name if it belongs to
* the Maven group `"io.spine.tools"`.
*
* Use `"NONE"` if you need no prefix before tool module names.
*
* @see artifactPrefix
*/
var toolArtifactPrefix: String = ""

/**
* Allows enabling publishing of [testJar] artifact, containing compilation output
* of "test" source set.
Expand Down Expand Up @@ -389,10 +411,26 @@ open class SpinePublishing(private val project: Project) {
/**
* Obtains an artifact ID for the given project.
*
* It consists of a project's name and [prefix][artifactPrefix]:
* `<artifactPrefix><project.name>`.
* @see artifactPrefix
* @see toolArtifactPrefix
*/
fun artifactId(project: Project): String = "$artifactPrefix${project.name}"
fun artifactId(project: Project): String {
if (project.isTool) {
check(!toolArtifactPrefix.isEmpty()) {
"Artifact prefix cannot be empty for tool modules. " +
"Please set the `toolArtifactPrefix` property in `spinePublishing`. " +
"Use `\"NONE\"` to have an empty prefix for tool modules."
}
val prefix =
if (toolArtifactPrefix == NONE_PREFIX) { "" }
else { toolArtifactPrefix }
return "$prefix${project.name}"
}
return "$artifactPrefix${project.name}"
}

private val Project.isTool: Boolean
get() = group == "io.spine.tools"

/**
* Ensures that all modules, marked as included into [testJar] publishing,
Expand Down
Loading
Loading