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
3 changes: 1 addition & 2 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ dependencies {
).forEach {
implementation(it)
}

testImplementation(platform("org.junit:junit-bom:5.11.4"))
testImplementation("org.junit.jupiter:junit-jupiter")
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
124 changes: 124 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,124 @@
/*
* 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)
}
}

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()
Comment thread
alexander-yevsyukov marked this conversation as resolved.

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()
Comment thread
alexander-yevsyukov marked this conversation as resolved.
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
@@ -0,0 +1,117 @@
/*
* 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.testfixtures.ProjectBuilder
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir

class UpdatePluginVersionTest {

@TempDir
lateinit var tempDir: File

private lateinit var buildFile: File

@BeforeEach
fun setUp() {
val subDir = File(tempDir, "subproject")
subDir.mkdir()
buildFile = File(subDir, "build.gradle.kts")
buildFile.writeText("""
plugins {
id("io.spine.validation") version "1.0.0"
id("other-plugin") version "0.1.0"
}
""".trimIndent())
}

@Test
fun `update plugin version in build file`() {
val project = ProjectBuilder.builder().build()
val task = project.tasks.register("updatePluginVersion", UpdatePluginVersion::class.java) {
directory.set(tempDir)
version.set("2.0.0-TEST")
pluginId.set("io.spine.validation")
}
task.get().update()

val updatedContent = buildFile.readText()
assertTrue(updatedContent.contains("""id("io.spine.validation") version "2.0.0-TEST""""))
assertTrue(updatedContent.contains("""id("other-plugin") version "0.1.0""""))
}

@Test
fun `update 'kotlin' plugin version when 'kotlinVersion' is set`() {
// Overwrite with a file that uses kotlin("jvm") syntax
buildFile.writeText(
"""
plugins {
kotlin("jvm") version "1.9.10"
id("io.spine.validation") version "1.0.0"
}
""".trimIndent()
)

val project = ProjectBuilder.builder().build()
val task = project.tasks.register("updatePluginVersion", UpdatePluginVersion::class.java) {
directory.set(tempDir)
version.set("2.0.0-TEST")
pluginId.set("io.spine.validation")
kotlinVersion.set("2.2.21")
}
task.get().update()

val updatedContent = buildFile.readText()
assertTrue(updatedContent.contains("""kotlin("jvm") version "2.2.21"""))
assertTrue(updatedContent.contains("""id("io.spine.validation") version "2.0.0-TEST"""))
}

@Test
fun `handle multiple spaces between id and version`() {
buildFile.writeText("""
plugins {
id("io.spine.validation") version "1.0.0"
}
""".trimIndent())

val project = ProjectBuilder.builder().build()
val task = project.tasks.register("updatePluginVersion", UpdatePluginVersion::class.java) {
directory.set(tempDir)
version.set("2.0.0-TEST")
pluginId.set("io.spine.validation")
}

task.get().update()

val updatedContent = buildFile.readText()
assertTrue(updatedContent.contains("""id("io.spine.validation") version "2.0.0-TEST""""))
}
}
Loading