From 7f3228ea6da00a34186689889d7fbbb798b5ce2f Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Mon, 28 Jul 2025 18:51:10 +0200 Subject: [PATCH 1/6] rename kxrpc to kotlinMultiplatform --- .../kotlinx/rpc/grpc/DefaultGrpcExtension.kt | 12 +++--- .../kotlin/kotlinx/rpc/proto/ProtocPlugin.kt | 26 ++++++------- .../main/kotlin/kotlinx/rpc/proto/consts.kt | 4 +- .../rpc/proto/kotlinMultiplatformPluginJar.kt | 39 +++++++++++++++++++ .../kotlinx/rpc/proto/kxrpcPluginJar.kt | 39 ------------------- grpc/grpc-core/build.gradle.kts | 8 +--- grpc/grpc-ktor-server/build.gradle.kts | 4 +- 7 files changed, 64 insertions(+), 68 deletions(-) create mode 100644 gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt delete mode 100644 gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kxrpcPluginJar.kt diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt index 7caa1bcd0..9147acd3f 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt @@ -16,7 +16,7 @@ import kotlinx.rpc.buf.tasks.registerGenerateBufYamlTask import kotlinx.rpc.proto.* import kotlinx.rpc.proto.ProtocPlugin.Companion.GRPC_JAVA import kotlinx.rpc.proto.ProtocPlugin.Companion.GRPC_KOTLIN -import kotlinx.rpc.proto.ProtocPlugin.Companion.KXRPC +import kotlinx.rpc.proto.ProtocPlugin.Companion.KOTLIN_MULTIPLATFORM import kotlinx.rpc.proto.ProtocPlugin.Companion.PROTOBUF_JAVA import kotlinx.rpc.util.ensureDirectoryExists import org.gradle.api.Action @@ -56,7 +56,7 @@ internal open class DefaultGrpcExtension @Inject constructor( init { project.configureBufExecutable() - project.configureKxRpcPluginJarConfiguration() + project.configureKotlinMultiplatformPluginJarConfiguration() createDefaultProtocPlugins() @@ -64,7 +64,7 @@ internal open class DefaultGrpcExtension @Inject constructor( protoSourceSet.protocPlugin(protocPlugins.protobufJava) protoSourceSet.protocPlugin(protocPlugins.grpcJava) protoSourceSet.protocPlugin(protocPlugins.grpcKotlin) - protoSourceSet.protocPlugin(protocPlugins.kxrpc) + protoSourceSet.protocPlugin(protocPlugins.kotlinMultiplatform) } project.afterEvaluate { @@ -269,12 +269,12 @@ internal open class DefaultGrpcExtension @Inject constructor( } private fun createDefaultProtocPlugins() { - protocPlugins.create(KXRPC) { + protocPlugins.create(KOTLIN_MULTIPLATFORM) { local { - javaJar(project.kxrpcProtocPluginJarPath) + javaJar(project.kotlinMultiplatformProtocPluginJarPath) } - options.put("debugOutput", "protobuf-kxrpc-plugin.log") + options.put("debugOutput", "protoc-gen-kotlin-multiplatform.log") options.put("messageMode", "interface") options.put("explicitApiModeEnabled", project.provider { project.the().explicitApi != ExplicitApiMode.Disabled diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProtocPlugin.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProtocPlugin.kt index 30fcf3077..d560c6c75 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProtocPlugin.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProtocPlugin.kt @@ -6,7 +6,7 @@ package kotlinx.rpc.proto import kotlinx.rpc.proto.ProtocPlugin.Companion.GRPC_JAVA import kotlinx.rpc.proto.ProtocPlugin.Companion.GRPC_KOTLIN -import kotlinx.rpc.proto.ProtocPlugin.Companion.KXRPC +import kotlinx.rpc.proto.ProtocPlugin.Companion.KOTLIN_MULTIPLATFORM import kotlinx.rpc.proto.ProtocPlugin.Companion.PROTOBUF_JAVA import kotlinx.rpc.util.OS import org.gradle.api.Action @@ -22,16 +22,16 @@ import org.gradle.kotlin.dsl.mapProperty import org.gradle.kotlin.dsl.property /** - * Access to the `kotlinx-rpc` protoc plugin. + * Access to the `kotlin-multiplatform` protoc plugin. */ -public val NamedDomainObjectContainer.kxrpc: NamedDomainObjectProvider - get() = named(KXRPC) +public val NamedDomainObjectContainer.kotlinMultiplatform: NamedDomainObjectProvider + get() = named(KOTLIN_MULTIPLATFORM) /** - * Configures the `kotlinx-rpc` protoc plugin. + * Configures the `kotlin-multiplatform` protoc plugin. */ -public fun NamedDomainObjectContainer.kxrpc(action: Action) { - kxrpc.configure(action) +public fun NamedDomainObjectContainer.kotlinMultiplatform(action: Action) { + kotlinMultiplatform.configure(action) } /** @@ -188,28 +188,28 @@ public open class ProtocPlugin( public companion object { /** - * The name of the kotlinx-rpc protoc plugin. + * The name of the `kotlin-multiplatform` protoc plugin. * - * @see [kxrpc] + * @see [kotlinMultiplatform] */ - public const val KXRPC: String = "kotlinx-rpc" + public const val KOTLIN_MULTIPLATFORM: String = "kotlin-multiplatform" /** - * The name of the protobuf-java protoc plugin. + * The name of the `protobuf-java` protoc plugin. * * @see [protobufJava] */ public const val PROTOBUF_JAVA: String = "java" /** - * The name of the grpc-java protoc plugin. + * The name of the `grpc-java` protoc plugin. * * @see [grpcJava] */ public const val GRPC_JAVA: String = "grpc-java" /** - * The name of the grpc-kotlin protoc plugin. + * The name of the `grpc-kotlin` protoc plugin. * * @see [grpcKotlin] */ diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/consts.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/consts.kt index dd800ad6f..dd9dfb093 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/consts.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/consts.kt @@ -52,8 +52,8 @@ public const val PROTO_FILES_DIR: String = "proto" public const val PROTO_FILES_IMPORT_DIR: String = "import" /** - * [Configuration] name for the `kotlinx-rpc` protoc plugin artifact. + * [Configuration] name for the `protoc-gen-kotlin-multiplatform` protoc plugin artifact. * * MUST be a single file. */ -public const val KXRPC_PLUGIN_JAR_CONFIGURATION: String = "kxrpcPluginJar" +public const val PROTOC_GEN_KOTLIN_MULTIPLATFORM_JAR_CONFIGURATION: String = "protocGenKotlinMultiplatformJar" diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt new file mode 100644 index 000000000..1e3735a09 --- /dev/null +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.proto + +import kotlinx.rpc.LIBRARY_VERSION +import org.gradle.api.Project +import org.gradle.api.provider.Provider + +/** + * Absolute path to the `protoc-gen-kotlin-multiplatform` jar. + * + * Can be used to customise the java executable path: + * ```kotlin + * rpc.grpc.protocPlugins.kotlinMultiplatform { + * local { + * javaJar(kotlinMultiplatformProtocPluginJarPath, provider { "my-path-to-java" }) + * } + * } + * ``` + */ +public val Project.kotlinMultiplatformProtocPluginJarPath: Provider + get() = project.configurations.named(PROTOC_GEN_KOTLIN_MULTIPLATFORM_JAR_CONFIGURATION).map { it.singleFile.absolutePath } + +internal fun Project.configureKotlinMultiplatformPluginJarConfiguration() { + configurations.create(PROTOC_GEN_KOTLIN_MULTIPLATFORM_JAR_CONFIGURATION) + + dependencies.add( + PROTOC_GEN_KOTLIN_MULTIPLATFORM_JAR_CONFIGURATION, + mapOf( + "group" to "org.jetbrains.kotlinx", + "name" to "protoc-gen-kotlin-multiplatform", + "version" to LIBRARY_VERSION, + "classifier" to "all", + "ext" to "jar", + ), + ) +} diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kxrpcPluginJar.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kxrpcPluginJar.kt deleted file mode 100644 index e5477a15f..000000000 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kxrpcPluginJar.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.rpc.proto - -import kotlinx.rpc.LIBRARY_VERSION -import org.gradle.api.Project -import org.gradle.api.provider.Provider - -/** - * Absolute path to the `kotlinx-rpc-protobuf-plugin` jar. - * - * Can be used to customise the java executable path: - * ```kotlin - * rpc.grpc.protocPlugins.kxrpc { - * local { - * javaJar(kxrpcProtocPluginJarPath, provider { "my-path-to-java" }) - * } - * } - * ``` - */ -public val Project.kxrpcProtocPluginJarPath: Provider - get() = project.configurations.named(KXRPC_PLUGIN_JAR_CONFIGURATION).map { it.singleFile.absolutePath } - -internal fun Project.configureKxRpcPluginJarConfiguration() { - configurations.create(KXRPC_PLUGIN_JAR_CONFIGURATION) - - dependencies.add( - KXRPC_PLUGIN_JAR_CONFIGURATION, - mapOf( - "group" to "org.jetbrains.kotlinx", - "name" to "kotlinx-rpc-protobuf-plugin", - "version" to LIBRARY_VERSION, - "classifier" to "all", - "ext" to "jar", - ), - ) -} diff --git a/grpc/grpc-core/build.gradle.kts b/grpc/grpc-core/build.gradle.kts index 180fbfcf9..4c6490588 100644 --- a/grpc/grpc-core/build.gradle.kts +++ b/grpc/grpc-core/build.gradle.kts @@ -3,13 +3,9 @@ */ import kotlinx.rpc.buf.tasks.BufGenerateTask -import kotlinx.rpc.proto.kxrpc +import kotlinx.rpc.proto.kotlinMultiplatform import org.gradle.kotlin.dsl.withType -/* - * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. - */ - plugins { alias(libs.plugins.conventions.kmp) alias(libs.plugins.kotlinx.rpc) @@ -74,7 +70,7 @@ rpc { grpc { val globalRootDir: String by extra - protocPlugins.kxrpc { + protocPlugins.kotlinMultiplatform { local { javaJar("$globalRootDir/protoc-gen/build/libs/protoc-gen-$version-all.jar") } diff --git a/grpc/grpc-ktor-server/build.gradle.kts b/grpc/grpc-ktor-server/build.gradle.kts index 30575b09b..8fa4115d7 100644 --- a/grpc/grpc-ktor-server/build.gradle.kts +++ b/grpc/grpc-ktor-server/build.gradle.kts @@ -3,7 +3,7 @@ */ import kotlinx.rpc.buf.tasks.BufGenerateTask -import kotlinx.rpc.proto.kxrpc +import kotlinx.rpc.proto.kotlinMultiplatform import org.gradle.kotlin.dsl.kotlin import org.gradle.kotlin.dsl.withType @@ -44,7 +44,7 @@ rpc { grpc { val globalRootDir: String by extra - protocPlugins.kxrpc { + protocPlugins.kotlinMultiplatform { local { javaJar("$globalRootDir/protoc-gen/build/libs/protoc-gen-$version-all.jar") } From 0fa85733549e7e1dbc147e686ff2da0588109b61 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Mon, 28 Jul 2025 18:58:07 +0200 Subject: [PATCH 2/6] Setup for Gradle Plugin tests --- gradle-plugin/build.gradle.kts | 90 ++++++- gradle-plugin/settings.gradle.kts | 6 + .../kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt | 55 ++++ .../test/kotlin/kotlinx/rpc/base/BaseTest.kt | 180 +++++++++++++ .../kotlin/kotlinx/rpc/base/GrpcBaseTest.kt | 236 ++++++++++++++++++ .../src/test/resources/projects/.keep | 0 .../projects/GrpcJvmProjectTest/.keep | 0 .../build.gradle.kts | 14 ++ .../src/main/proto/some.proto | 5 + .../no_grpc/build.gradle.kts | 10 + .../test/resources/template.gradle.properties | 20 ++ .../resources/template.settings.gradle.kts | 18 ++ versions-root/libs.versions.toml | 1 + 13 files changed, 627 insertions(+), 8 deletions(-) create mode 100644 gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt create mode 100644 gradle-plugin/src/test/kotlin/kotlinx/rpc/base/BaseTest.kt create mode 100644 gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt create mode 100644 gradle-plugin/src/test/resources/projects/.keep create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/.keep create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/minimal_grpc_configuration/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/minimal_grpc_configuration/src/main/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/no_grpc/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/template.gradle.properties create mode 100644 gradle-plugin/src/test/resources/template.settings.gradle.kts diff --git a/gradle-plugin/build.gradle.kts b/gradle-plugin/build.gradle.kts index 4ccce943b..789cc0825 100644 --- a/gradle-plugin/build.gradle.kts +++ b/gradle-plugin/build.gradle.kts @@ -21,7 +21,28 @@ kotlin { } dependencies { - compileOnly(libs.kotlin.gradle.plugin) + implementation(libs.kotlin.gradle.plugin) + + testImplementation(libs.kotlin.gradle.plugin) + testImplementation(gradleTestKit()) + testImplementation(platform(libs.junit5.bom)) + testImplementation(libs.kotlin.test.junit5) + testImplementation(libs.junit5.jupiter) + testImplementation(libs.junit5.jupiter.api) + testRuntimeOnly(libs.junit5.platform.launcher) + + testImplementation(libs.logback.classic) +} + +tasks.test { + val forwardOutput: Boolean = (properties.getOrDefault("gradle.test.forward.output", "false") + as String).toBooleanStrictOrNull() ?: false + + systemProperty("gradle.test.forward.output", forwardOutput) + + useJUnitPlatform() + + dependsOn(gradle.includedBuild("protoc-gen").task(":publishAllPublicationsToBuildRepoRepository")) } // This block is needed to show plugin tasks on --dry-run @@ -46,7 +67,7 @@ gradlePlugin { } } -abstract class GeneratePluginVersionTask @Inject constructor( +abstract class GeneratePluginVersionsTask @Inject constructor( @get:Input val libraryVersion: String, @get:Input val protobufVersion: String, @get:Input val grpcVersion: String, @@ -96,15 +117,15 @@ public const val BUF_TOOL_VERSION: String = "$bufToolVersion" ) } - companion object { - const val NAME = "generatePluginVersion" + companion object Companion { + const val NAME = "generatePluginVersions" } } -val sourcesDir = File(project.layout.buildDirectory.asFile.get(), "generated-sources/pluginVersion") +val sourcesDir = File(project.layout.buildDirectory.asFile.get(), "generated-sources/pluginVersions") -val generatePluginVersionTask = tasks.register( - GeneratePluginVersionTask.NAME, +val generatePluginVersionsTask = tasks.register( + GeneratePluginVersionsTask.NAME, version.toString(), libs.versions.protobuf.asProvider().get(), libs.versions.grpc.asProvider().get(), @@ -113,10 +134,63 @@ val generatePluginVersionTask = tasks.register( sourcesDir, ) +abstract class GenerateTestVersionTask @Inject constructor( + @get:Input val kotlinVersion: String, + @get:Input val protobufVersion: String, + @get:Input val grpcVersion: String, + @get:Input val grpcKotlinVersion: String, + @get:Input val buildRepo: String, + @get:OutputDirectory val sourcesDir: File +) : DefaultTask() { + @TaskAction + fun generate() { + val sourceFile = File(sourcesDir, "Versions.kt") + + sourceFile.writeText( + """ +// This file is generated by a $NAME gradle task. Do not modify manually. + +package kotlinx.rpc + +const val KOTLIN_VERSION: String = "$kotlinVersion" + +const val BUILD_REPO: String = "$buildRepo" + +// can't use from generatePluginVersionsTask bacause Gradle messes up caches +const val TEST_PROTOBUF_VERSION: String = "$protobufVersion" +const val TEST_GRPC_VERSION: String = "$grpcVersion" +const val TEST_GRPC_KOTLIN_VERSION: String = "$grpcKotlinVersion" + +""".trimIndent() + ) + } + + companion object { + const val NAME = "generateTestVersions" + } +} + +val testSourcesDir = File(project.layout.buildDirectory.asFile.get(), "generated-sources/testVersions") + +val globalRootDir: String by extra + +val generateTestVersionsTask = tasks.register( + GenerateTestVersionTask.NAME, + libs.versions.kotlin.lang.get(), + libs.versions.protobuf.asProvider().get(), + libs.versions.grpc.asProvider().get(), + libs.versions.grpc.kotlin.get(), + File(globalRootDir).resolve("build/repo").absolutePath, + testSourcesDir, +) + kotlin { sourceSets { main { - kotlin.srcDir(generatePluginVersionTask.map { it.sourcesDir }) + kotlin.srcDir(generatePluginVersionsTask.map { it.sourcesDir }) + } + test { + kotlin.srcDir(generateTestVersionsTask.map { it.sourcesDir }) } } } diff --git a/gradle-plugin/settings.gradle.kts b/gradle-plugin/settings.gradle.kts index 264b38dd0..4482eb05b 100644 --- a/gradle-plugin/settings.gradle.kts +++ b/gradle-plugin/settings.gradle.kts @@ -11,6 +11,12 @@ pluginManagement { includeBuild("../gradle-conventions-settings") } +dependencyResolutionManagement { + // for tests + includeBuild("../protoc-gen") + includeBuild("../compiler-plugin") +} + plugins { id("conventions-repositories") id("conventions-version-resolution") diff --git a/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt b/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt new file mode 100644 index 000000000..98e87ccb2 --- /dev/null +++ b/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc + +import kotlinx.rpc.base.GrpcBaseTest +import org.gradle.testkit.runner.TaskOutcome +import org.junit.jupiter.api.TestInstance +import kotlin.io.path.Path +import kotlin.test.Test +import kotlin.test.assertEquals + +@TestInstance(TestInstance.Lifecycle.PER_METHOD) +class GrpcJvmProjectTest : GrpcBaseTest() { + override val isKmp: Boolean = false + + @Test + fun `Minimal gRPC Configuration`() { + val result = runGradle(bufGenerateMain) + + assertEquals(TaskOutcome.SUCCESS, result.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.SUCCESS, result.protoTaskOutcome(processMainProtoFiles)) + assertEquals(TaskOutcome.SUCCESS, result.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.SUCCESS, result.protoTaskOutcome(generateBufGenYamlMain)) + + result.assertProtoTaskNotExecuted(bufGenerateTest) + result.assertProtoTaskNotExecuted(processTestProtoFiles) + result.assertProtoTaskNotExecuted(processTestImportProtoFiles) + result.assertProtoTaskNotExecuted(generateBufYamlTest) + result.assertProtoTaskNotExecuted(generateBufGenYamlTest) + + assertSourceCodeGenerated( + mainSourceSet, + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt") + ) + + assertWorkspaceProtoFilesCopied(mainSourceSet, Path("some.proto")) + assertWorkspaceImportProtoFilesCopied(mainSourceSet) + } + + @Test + fun `No gRPC`() { + runNonExistentTask(bufGenerateMain) + runNonExistentTask(bufGenerateTest) + runNonExistentTask(processMainProtoFiles) + runNonExistentTask(processTestProtoFiles) + runNonExistentTask(processTestImportProtoFiles) + runNonExistentTask(generateBufYamlMain) + runNonExistentTask(generateBufYamlTest) + runNonExistentTask(generateBufGenYamlMain) + runNonExistentTask(generateBufGenYamlTest) + } +} diff --git a/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/BaseTest.kt b/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/BaseTest.kt new file mode 100644 index 000000000..febb3e71b --- /dev/null +++ b/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/BaseTest.kt @@ -0,0 +1,180 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.base + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.TestInfo +import org.junit.jupiter.api.TestInstance +import java.nio.file.Path +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.absolutePathString +import kotlin.io.path.copyTo +import kotlin.io.path.copyToRecursively +import kotlin.io.path.readText +import kotlin.io.path.writeText +import kotlinx.rpc.KOTLIN_VERSION +import kotlinx.rpc.BUILD_REPO +import kotlin.io.path.absolute +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteRecursively + +@OptIn(ExperimentalPathApi::class) +@TestInstance(TestInstance.Lifecycle.PER_METHOD) +abstract class BaseTest { + private lateinit var projectDir: Path + + @BeforeEach + protected fun setup(testInfo: TestInfo) { + TEST_KIT_PATH.createDirectories() + + val testClassName = testInfo.testClass.get().simpleName + val testMethodName = testInfo.testMethod.get().name + .replace(nameRegex, "_") + .lowercase() + + val baseDir = TEST_PROJECTS_PATH + .resolve(testClassName) + .resolve(testMethodName) + + baseDir.deleteRecursively() + baseDir.createDirectories() + + projectDir = baseDir.resolve(PROJECT_DIR) + val buildCacheDir = baseDir.resolve(BUILD_CACHE_DIR) + + projectDir.createDirectories() + buildCacheDir.createDirectories() + + val settingsTemplate = RESOURCES_PATH.resolve(SETTINGS_TEMPLATE) + ?: error("template.settings.gradle.kts not found") + val propertiesTemplate = RESOURCES_PATH.resolve(PROPERTIES_TEMPLATE) + ?: error("template.gradle.properties not found") + + val settingsFile = projectDir.resolve("settings.gradle.kts") + val propertiesFile = projectDir.resolve("gradle.properties") + + settingsTemplate.copyTo(settingsFile) + propertiesTemplate.copyTo(propertiesFile) + + val projectName = "$testClassName-$testMethodName" + settingsFile.replace("", projectName) + settingsFile.replace("", buildCacheDir.absolutePathString()) + settingsFile.replace("", BUILD_REPO) + + val testTemplateDirectory = RESOURCES_PATH.resolve(PROJECTS_DIR) + .resolve(testClassName) + .resolve(testMethodName) + + testTemplateDirectory.copyToRecursively(projectDir, followLinks = false, overwrite = true) + + val buildScriptFile = projectDir.resolve("build.gradle.kts") + buildScriptFile.replace("", KOTLIN_VERSION) + + println(""" + Setup project '$projectName' + - in directory: ${projectDir.absolutePathString()} + - from directory: ${testTemplateDirectory.absolutePathString()} + """.trimIndent()) + } + + private fun runGradleInternal( + task: String, + vararg args: String, + body: GradleRunner.() -> BuildResult, + ): BuildResult { + val gradleRunner = GradleRunner.create() + .withProjectDir(projectDir.absolute().toFile()) + .withTestKitDir(TEST_KIT_PATH.absolute().toFile()) + .withPluginClasspath() + .withArguments( + listOfNotNull( + task, + "--stacktrace", + "--info", + "-Dorg.gradle.kotlin.dsl.scriptCompilationAvoidance=false", + *args, + ) + ).apply { + if (forwardOutput) { + forwardOutput() + } + } + + println("Running Gradle task '$task' with arguments: [${args.joinToString()}]") + return gradleRunner.body() + } + + protected fun runBaseTest(body: TestEnv.() -> Unit) { + runTest(TestEnv(), body) + } + + protected fun runTest(testEnv: T, body: T.() -> Unit) { + try { + testEnv.body() + } catch (e: Throwable) { + val output = testEnv.latestBuild?.output + if (output != null) { + println("Latest gradle build output:") + println(output) + } else { + println("No gradle build output available") + } + throw e + } + } + + open inner class TestEnv { + val projectDir: Path get() = this@BaseTest.projectDir + var latestBuild: BuildResult? = null + private set + + fun runGradle(task: String, vararg args: String): BuildResult { + return runGradleInternal(task, *args) { + build().also { latestBuild = it } + } + } + + fun runGradleToFail(task: String, vararg args: String): BuildResult { + return runGradleInternal(task, *args) { + buildAndFail().also { latestBuild = it } + } + } + + fun runNonExistentTask(task: String): BuildResult { + return runGradleToFail(task).apply { + assertNoTask(task) + } + } + + fun BuildResult.assertNoTask(name: String) { + assert(output.contains("Task '$name' not found")) { + "Task '$name' should not be present in the project" + } + } + } + + protected fun Path.replace(oldValue: String, newValue: String) { + writeText(readText().replace(oldValue, newValue)) + } + + companion object { + private val forwardOutput = System.getProperty("gradle.test.forward.output") + ?.toBooleanStrictOrNull() ?: false + + private val nameRegex = Regex("[ .,-]") + + private val TEST_PROJECTS_PATH = Path.of("build", "gradle-test") + private val TEST_KIT_PATH = Path.of("build", "test-kit") + private const val BUILD_CACHE_DIR = "build-cache" + private const val PROJECT_DIR = "project" + + private val RESOURCES_PATH = Path.of("src", "test", "resources") + private const val SETTINGS_TEMPLATE = "template.settings.gradle.kts" + private const val PROPERTIES_TEMPLATE = "template.gradle.properties" + private const val PROJECTS_DIR = "projects" + } +} diff --git a/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt b/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt new file mode 100644 index 000000000..50c0563ab --- /dev/null +++ b/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt @@ -0,0 +1,236 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.base + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome +import org.intellij.lang.annotations.Language +import org.junit.jupiter.api.TestInstance +import java.nio.file.Path +import kotlin.io.path.ExperimentalPathApi +import kotlin.io.path.absolutePathString +import kotlin.io.path.deleteRecursively +import kotlin.io.path.exists +import kotlin.io.path.extension +import kotlin.io.path.isRegularFile +import kotlin.io.path.pathString +import kotlin.io.path.readLines +import kotlin.io.path.relativeTo +import kotlin.io.path.walk +import kotlin.lazy +import kotlin.test.assertEquals +import kotlin.test.fail + +@TestInstance(TestInstance.Lifecycle.PER_METHOD) +abstract class GrpcBaseTest : BaseTest() { + abstract val isKmp: Boolean + + protected fun runGrpcTest(test: GrpcTestEnv.() -> Unit) { + runTest(GrpcTestEnv(), test) + } + + inner class GrpcTestEnv : TestEnv() { + fun BuildResult.protoTaskOutcome(name: String): TaskOutcome { + return tasks.find { it.path == ":$name" }?.outcome + ?: fail("Task ':$name' was not present in the build result") + } + + fun BuildResult.assertProtoTaskNotExecuted(name: String) { + val task = tasks.find { it.path == ":$name" } + if (task != null) { + fail("Task ':$name' was present in the build result, but it shouldn't have been executed") + } + } + + fun assertSourceCodeGenerated(sourceSet: String, vararg files: Path) { + val dir = protoBuildDirGenerated.resolve(sourceSet).resolve(KOTLIN_MULTIPLATFORM_DIR) + if (files.isNotEmpty()) { + assert(dir.exists()) { + "Directory '$dir' with generated sources does not exist" + } + } + + files.forEach { file -> + assert(dir.resolve(file).exists()) { + "File 'file://${file.absolutePathString()}' in '$dir' does not exist" + } + } + } + + fun assertSourceCodeNotGenerated(sourceSet: String, vararg files: Path) { + val dir = protoBuildDirGenerated.resolve(sourceSet).resolve(KOTLIN_MULTIPLATFORM_DIR) + + files.forEach { file -> + assert(!dir.resolve(file).exists()) { + "File 'file://${file.absolutePathString()}' in '$dir' should not exist" + } + } + } + + @OptIn(ExperimentalPathApi::class) + private fun assertWorkspaceProtoFilesCopiedInternal(vararg files: Path, sourceSet: String, dir: String) { + val protoSources = protoBuildDirSourceSets.resolve(sourceSet).resolve(dir) + val included = files.map { file -> + val resolved = protoSources.resolve(file) + assert(resolved.exists()) { + "File 'file://${file.absolutePathString()}' in '$protoSources' does not exist" + } + resolved.relativeTo(protoSources).pathString + }.toSet() + + protoSources.walk().forEach { + if (it.isRegularFile() && it.extension == "proto" && it.relativeTo(protoSources).pathString !in included) { + fail("File 'file://${it.absolutePathString()}' in '$protoSources' is not expected") + } + } + } + + fun assertWorkspaceProtoFilesCopied(sourceSet: String, vararg files: Path) { + assertWorkspaceProtoFilesCopiedInternal(*files, sourceSet = sourceSet, dir = "proto") + } + + fun assertWorkspaceImportProtoFilesCopied(sourceSet: String, vararg files: Path) { + assertWorkspaceProtoFilesCopiedInternal(*files, sourceSet = sourceSet, dir = "import") + } + + @OptIn(ExperimentalPathApi::class) + fun cleanProtoBuildDir() { + protoBuildDir.deleteRecursively() + } + + fun assertBufGenYaml(sourceSet: String, @Language("Yaml") content: String) { + val file = protoBuildDirSourceSets + .resolve(sourceSet) + .resolve("buf.gen.yaml") + + assert(file.exists()) { + "File '${file.absolutePathString()}' does not exist" + } + + val fileContent = file.readLines().joinToString("\n") { + if (it.contains("protoc-gen-kotlin-multiplatform")) { + it.replace(localPluginExecRegex, "[protoc-gen-kotlin-multiplatform]") + } else { + it + } + } + + assertEquals(content.trimIndent(), fileContent.trimIndent()) + } + + private val localPluginExecRegex = "\\[.*?]".toRegex() + + fun BuildResult.assertMainTaskExecuted( + protoFiles: List, + generatedFiles: List, + ) { + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(processMainProtoFiles)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(generateBufGenYamlMain)) + + assertProtoTaskNotExecuted(bufGenerateTest) + assertProtoTaskNotExecuted(processTestProtoFiles) + assertProtoTaskNotExecuted(processTestImportProtoFiles) + assertProtoTaskNotExecuted(generateBufYamlTest) + assertProtoTaskNotExecuted(generateBufGenYamlTest) + + assertSourceCodeGenerated(mainSourceSet, *generatedFiles.toTypedArray()) + assertSourceCodeNotGenerated(testSourceSet, *generatedFiles.toTypedArray()) + + assertWorkspaceProtoFilesCopied(mainSourceSet, *protoFiles.toTypedArray()) + assertWorkspaceImportProtoFilesCopied(mainSourceSet) + + assertWorkspaceProtoFilesCopied(testSourceSet) + assertWorkspaceImportProtoFilesCopied(testSourceSet) + } + + fun BuildResult.assertTestTaskExecuted( + protoFiles: List, + importProtoFiles: List, + generatedFiles: List, + importGeneratedFiles: List, + ) { + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(bufGenerateTest)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(processTestProtoFiles)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(processTestImportProtoFiles)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(generateBufYamlTest)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(generateBufGenYamlTest)) + + val mainGenerateOutcome = if (importProtoFiles.isEmpty()) { + TaskOutcome.SKIPPED + } else { + TaskOutcome.SUCCESS + } + + assertEquals(mainGenerateOutcome, protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(processMainProtoFiles)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.SUCCESS, protoTaskOutcome(generateBufGenYamlMain)) + + assertSourceCodeGenerated(testSourceSet, *generatedFiles.toTypedArray()) + assertSourceCodeNotGenerated(mainSourceSet, *generatedFiles.toTypedArray()) + + assertSourceCodeGenerated(mainSourceSet, *importGeneratedFiles.toTypedArray()) + assertSourceCodeNotGenerated(testSourceSet, *importGeneratedFiles.toTypedArray()) + + assertWorkspaceProtoFilesCopied(testSourceSet, *protoFiles.toTypedArray()) + assertWorkspaceImportProtoFilesCopied(testSourceSet, *importProtoFiles.toTypedArray()) + + assertWorkspaceProtoFilesCopied(mainSourceSet, *importProtoFiles.toTypedArray()) + assertWorkspaceImportProtoFilesCopied(mainSourceSet) + } + + val mainSourceSet = if (isKmp) "${KMP_SOURCE_SET}Main" else "main" + val testSourceSet = if (isKmp) "${KMP_SOURCE_SET}Test" else "test" + val bufGenerateMain = if (isKmp) "bufGenerate${KMP_SOURCE_SET_CAPITAL}Main" else "bufGenerateMain" + val bufGenerateTest = if (isKmp) "bufGenerate${KMP_SOURCE_SET_CAPITAL}Test" else "bufGenerateTest" + val processMainProtoFiles = + if (isKmp) "process${KMP_SOURCE_SET_CAPITAL}MainProtoFiles" else "processMainProtoFiles" + val processTestProtoFiles = + if (isKmp) "process${KMP_SOURCE_SET_CAPITAL}TestProtoFiles" else "processTestProtoFiles" + val processTestImportProtoFiles = + if (isKmp) "process${KMP_SOURCE_SET_CAPITAL}TestImportProtoFiles" else "processTestImportProtoFiles" + val generateBufYamlMain = if (isKmp) "generateBufYaml${KMP_SOURCE_SET_CAPITAL}Main" else "generateBufYamlMain" + val generateBufYamlTest = if (isKmp) "generateBufYaml${KMP_SOURCE_SET_CAPITAL}Test" else "generateBufYamlTest" + val generateBufGenYamlMain = + if (isKmp) "generateBufGenYaml${KMP_SOURCE_SET_CAPITAL}Main" else "generateBufGenYamlMain" + val generateBufGenYamlTest = + if (isKmp) "generateBufGenYaml${KMP_SOURCE_SET_CAPITAL}Test" else "generateBufGenYamlTest" + + val protoBuildDir: Path by lazy { + projectDir + .resolve("build") + .resolve("protoBuild") + } + + val TestEnv.protoBuildDirSourceSets: Path by lazy { + protoBuildDir + .resolve("sourceSets") + } + + val TestEnv.protoBuildDirGenerated: Path by lazy { + protoBuildDir + .resolve("generated") + } + + val mainProtoFileSources = projectDir + .resolve("src") + .resolve(mainSourceSet) + .resolve("proto") + + val testProtoFileSources = projectDir + .resolve("src") + .resolve(testSourceSet) + .resolve("proto") + } + + companion object { + private const val KMP_SOURCE_SET = "jvm" + private val KMP_SOURCE_SET_CAPITAL = KMP_SOURCE_SET.replaceFirstChar(Char::uppercaseChar) + private const val KOTLIN_MULTIPLATFORM_DIR = "kotlin-multiplatform" + const val RPC_INTERNAL = "_rpc_internal" + } +} diff --git a/gradle-plugin/src/test/resources/projects/.keep b/gradle-plugin/src/test/resources/projects/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/.keep b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/minimal_grpc_configuration/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/minimal_grpc_configuration/build.gradle.kts new file mode 100644 index 000000000..e9b01b47d --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/minimal_grpc_configuration/build.gradle.kts @@ -0,0 +1,14 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/minimal_grpc_configuration/src/main/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/minimal_grpc_configuration/src/main/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/minimal_grpc_configuration/src/main/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/no_grpc/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/no_grpc/build.gradle.kts new file mode 100644 index 000000000..cc6194819 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/no_grpc/build.gradle.kts @@ -0,0 +1,10 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} diff --git a/gradle-plugin/src/test/resources/template.gradle.properties b/gradle-plugin/src/test/resources/template.gradle.properties new file mode 100644 index 000000000..c94b4e963 --- /dev/null +++ b/gradle-plugin/src/test/resources/template.gradle.properties @@ -0,0 +1,20 @@ +# +# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. +# + +kotlin.code.style=official + +kotlin.native.ignoreDisabledTargets=true + +kotlin.daemon.jvmargs=-Xmx8g -XX:+HeapDumpOnOutOfMemoryError +kotlin.daemon.useFallbackStrategy=false + +org.gradle.jvmargs=-Xmx4g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC -XX:MaxMetaspaceSize=768m +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.workers.max=2 +org.gradle.caching=true +org.gradle.configuration-cache=true + +# development mode for kotlinx.rpc gradle plugin. Uses local project paths to apply the compiler plugin +kotlinx.rpc.plugin.internalDevelopment=true diff --git a/gradle-plugin/src/test/resources/template.settings.gradle.kts b/gradle-plugin/src/test/resources/template.settings.gradle.kts new file mode 100644 index 000000000..56e4c1ebd --- /dev/null +++ b/gradle-plugin/src/test/resources/template.settings.gradle.kts @@ -0,0 +1,18 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +rootProject.name = "" + +buildCache { + local { + directory = "" + } +} + +dependencyResolutionManagement { + repositories { + mavenCentral() + maven("") + } +} diff --git a/versions-root/libs.versions.toml b/versions-root/libs.versions.toml index 8c7137f4a..39d0d6517 100644 --- a/versions-root/libs.versions.toml +++ b/versions-root/libs.versions.toml @@ -84,6 +84,7 @@ logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "lo junit4 = { module = "junit:junit", version.ref = "junit4" } junit5-bom = { module = "org.junit:junit-bom", version.ref = "junit5" } junit5-jupiter = { module = "org.junit.jupiter:junit-jupiter" } +junit5-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api" } junit5-platform-commons = { module = "org.junit.platform:junit-platform-commons" } junit5-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" } junit5-platform-runner = { module = "org.junit.platform:junit-platform-runner" } From b7df24d6c47c68ad52abde019e7ea364b8933f0e Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Tue, 29 Jul 2025 17:06:21 +0200 Subject: [PATCH 3/6] Added all gradle plugin tests --- .../kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt | 279 ++++++++++++++++-- .../kotlin/kotlinx/rpc/GrpcKmpProjectTest.kt | 125 ++++++++ .../build.gradle.kts | 44 +++ .../custom_buf_cli_flags/build.gradle.kts | 30 ++ .../custom_buf_cli_flags/some.buf.yaml | 1 + .../src/main/proto/some.proto} | 0 .../build.gradle.kts | 25 ++ .../build.gradle.kts | 31 ++ .../src/main/proto/exclude.proto} | 0 .../src/main/proto/exclude/no1.proto | 0 .../src/main/proto/exclude/no2.proto | 0 .../src/main/proto/ok/ok.proto | 0 .../src/main/proto/some.proto | 5 + .../src/test/proto/include.proto | 0 .../src/test/proto/include/yes1.proto | 0 .../src/test/proto/include/yes2.proto | 0 .../src/test/proto/other.proto | 5 + .../proto/some/package/hello/world/file.proto | 0 .../build.gradle.kts | 14 + .../src/main/proto/some.proto | 5 + .../src/test/proto/other.proto | 5 + .../no_grpc/build.gradle.kts | 6 + .../build.gradle.kts | 15 + .../src/main/proto/some.proto | 5 + .../src/test/proto/other.proto | 5 + .../build.gradle.kts | 23 ++ .../src/main/proto/some.proto | 5 + .../test_only_sources/build.gradle.kts | 14 + .../src/test/proto/some.proto | 5 + .../build.gradle.kts | 18 ++ .../src/jvmMain/proto/some.proto | 5 + .../src/jvmTest/proto/other.proto | 5 + .../build.gradle.kts | 18 ++ .../src/jvmMain/proto/some.proto | 5 + .../no_grpc/build.gradle.kts | 16 + .../no_jvm_targets/build.gradle.kts | 21 ++ .../test_only_sources/build.gradle.kts | 18 ++ .../src/jvmTest/proto/some.proto | 5 + .../with_other_targets/build.gradle.kts | 25 ++ .../src/jvmMain/proto/some.proto | 5 + 40 files changed, 768 insertions(+), 20 deletions(-) create mode 100644 gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcKmpProjectTest.kt create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/can_add_custom_protoc_plugins/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/some.buf.yaml rename gradle-plugin/src/test/resources/projects/{.keep => GrpcJvmProjectTest/custom_buf_cli_flags/src/main/proto/some.proto} (100%) create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_protoc_plugins_must_declare_an_artifact/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/build.gradle.kts rename gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/{.keep => exclude_and_include_in_protosourcesets/src/main/proto/exclude.proto} (100%) create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/exclude/no1.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/exclude/no2.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/ok/ok.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include/yes1.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include/yes2.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/other.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/some/package/hello/world/file.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/src/main/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/src/test/proto/other.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/src/main/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/src/test/proto/other.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/skip_generation_when_no_proto_files/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/skip_generation_when_no_proto_files/src/main/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/test_only_sources/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/test_only_sources/src/test/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/src/jvmMain/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/src/jvmTest/proto/other.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/minimal_grpc_configuration/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/minimal_grpc_configuration/src/jvmMain/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/no_grpc/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/no_jvm_targets/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/test_only_sources/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/test_only_sources/src/jvmTest/proto/some.proto create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/with_other_targets/build.gradle.kts create mode 100644 gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/with_other_targets/src/jvmMain/proto/some.proto diff --git a/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt b/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt index 98e87ccb2..d271f1f42 100644 --- a/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt +++ b/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt @@ -16,32 +16,22 @@ class GrpcJvmProjectTest : GrpcBaseTest() { override val isKmp: Boolean = false @Test - fun `Minimal gRPC Configuration`() { + fun `Minimal gRPC Configuration`() = runGrpcTest { val result = runGradle(bufGenerateMain) - assertEquals(TaskOutcome.SUCCESS, result.protoTaskOutcome(bufGenerateMain)) - assertEquals(TaskOutcome.SUCCESS, result.protoTaskOutcome(processMainProtoFiles)) - assertEquals(TaskOutcome.SUCCESS, result.protoTaskOutcome(generateBufYamlMain)) - assertEquals(TaskOutcome.SUCCESS, result.protoTaskOutcome(generateBufGenYamlMain)) - - result.assertProtoTaskNotExecuted(bufGenerateTest) - result.assertProtoTaskNotExecuted(processTestProtoFiles) - result.assertProtoTaskNotExecuted(processTestImportProtoFiles) - result.assertProtoTaskNotExecuted(generateBufYamlTest) - result.assertProtoTaskNotExecuted(generateBufGenYamlTest) - - assertSourceCodeGenerated( - mainSourceSet, - Path("Some.kt"), - Path(RPC_INTERNAL, "Some.kt") + result.assertMainTaskExecuted( + protoFiles = listOf( + Path("some.proto") + ), + generatedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ) ) - - assertWorkspaceProtoFilesCopied(mainSourceSet, Path("some.proto")) - assertWorkspaceImportProtoFilesCopied(mainSourceSet) } @Test - fun `No gRPC`() { + fun `No gRPC`() = runGrpcTest { runNonExistentTask(bufGenerateMain) runNonExistentTask(bufGenerateTest) runNonExistentTask(processMainProtoFiles) @@ -52,4 +42,253 @@ class GrpcJvmProjectTest : GrpcBaseTest() { runNonExistentTask(generateBufGenYamlMain) runNonExistentTask(generateBufGenYamlTest) } + + @Test + fun `Test-Only Sources`() = runGrpcTest { + val result = runGradle(bufGenerateTest) + + result.assertTestTaskExecuted( + protoFiles = listOf( + Path("some.proto"), + ), + importProtoFiles = emptyList(), + generatedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ), + importGeneratedFiles = emptyList() + ) + } + + @Test + fun `Main and Test Mixed Sources`() = runGrpcTest { + val mainRun = runGradle(bufGenerateMain) + + mainRun.assertMainTaskExecuted( + protoFiles = listOf( + Path("some.proto") + ), + generatedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ) + ) + + cleanProtoBuildDir() + + val testRun = runGradle(bufGenerateTest) + + testRun.assertTestTaskExecuted( + protoFiles = listOf( + Path("other.proto") + ), + importProtoFiles = listOf( + Path("some.proto") + ), + generatedFiles = listOf( + Path("Other.kt"), + Path(RPC_INTERNAL, "Other.kt"), + ), + importGeneratedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ) + ) + } + + @Test + fun `Exclude and Include in protoSourceSets`() = runGrpcTest { + runGradle(processMainProtoFiles) + + assertWorkspaceProtoFilesCopied( + mainSourceSet, + Path("some.proto"), + Path("ok", "ok.proto"), + ) + + runGradle(processTestProtoFiles) + + assertWorkspaceProtoFilesCopied( + testSourceSet, + Path("include.proto"), + Path("some", "package", "hello", "world", "file.proto"), + Path("include", "yes1.proto"), + Path("include", "yes2.proto"), + ) + + runGradle(processTestImportProtoFiles) + + assertWorkspaceImportProtoFilesCopied( + testSourceSet, + Path("some.proto"), + Path("ok", "ok.proto"), + ) + } + + @Test + fun `Can Add Custom Protoc Plugins`() = runGrpcTest { + runGradle(generateBufGenYamlMain) + + assertBufGenYaml( + sourceSet = mainSourceSet, + content = """ +version: v2 +clean: true +plugins: + - remote: buf.build/protocolbuffers/java:v${TEST_PROTOBUF_VERSION.substringAfter(".")} + out: java + - remote: buf.build/grpc/java:v$TEST_GRPC_VERSION + out: grpc-java + - remote: buf.build/grpc/kotlin:v$TEST_GRPC_KOTLIN_VERSION + out: grpc-kotlin + - local: [protoc-gen-kotlin-multiplatform] + out: kotlin-multiplatform + opt: + - debugOutput=protoc-gen-kotlin-multiplatform.log + - messageMode=interface + - explicitApiModeEnabled=true + - local: [path, to, protoc-gen-myplugin.exe] + out: myPlugin + opt: + - hello=world + - foo=bar + strategy: all + include_imports: true + include_wkt: false + types: + - my.type.Yay + exclude_types: + - my.type.Nope + - remote: my.remote.plugin + out: myRemotePlugin +inputs: + - directory: proto + """.trimIndent() + ) + } + + @Test + fun `Custom Protoc Plugins Must Declare an Artifact`() = runGrpcTest { + val result = runGradleToFail(generateBufGenYamlMain) + assert(result.output.contains("Artifact is not specified for protoc plugin myPlugin")) + } + + private val cliFlagsRegex = "- Buf Arguments: \\[.*?, generate, --output, .*?, --include-imports, --include-wkt, --error-format, json, --config, some\\.buf\\.yaml, --log-format, json, --timeout, 60s]".toRegex() + + @Test + fun `Custom Buf CLI Flags`() = runGrpcTest { + val result = runGradleToFail(bufGenerateMain) + assert(result.output.contains("could not read file: open some.buf.yaml: no such file or directory")) { + "Expected failure due to missing some.buf.yaml file" + } + + val cliArgsLine = result.output.lines().first { it.contains("- Buf Arguments:") } + assert(cliArgsLine.contains(cliFlagsRegex)) { + "Buf CLI flags are not correct: $cliArgsLine" + } + } + + @Test + fun `Skip Generation When No Proto Files`() = runGrpcTest { + val result = runGradle(bufGenerateMain) + + assertEquals(TaskOutcome.SKIPPED, result.protoTaskOutcome(bufGenerateMain)) + } + + @Test + fun `Proto Tasks Are Cached Properly`() = runGrpcTest { + val firstRunMain = runGradle(bufGenerateMain) + + assertEquals(TaskOutcome.SUCCESS, firstRunMain.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.SUCCESS, firstRunMain.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.SUCCESS, firstRunMain.protoTaskOutcome(generateBufGenYamlMain)) + assertEquals(TaskOutcome.SUCCESS, firstRunMain.protoTaskOutcome(processMainProtoFiles)) + + val secondRunMain = runGradle(bufGenerateMain) + + assertEquals(TaskOutcome.UP_TO_DATE, secondRunMain.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunMain.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunMain.protoTaskOutcome(generateBufGenYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunMain.protoTaskOutcome(processMainProtoFiles)) + + cleanProtoBuildDir() + + val thirdRunMain = runGradle(bufGenerateMain) + + assertEquals(TaskOutcome.SUCCESS, thirdRunMain.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.SUCCESS, thirdRunMain.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.SUCCESS, thirdRunMain.protoTaskOutcome(generateBufGenYamlMain)) + assertEquals(TaskOutcome.SUCCESS, thirdRunMain.protoTaskOutcome(processMainProtoFiles)) + + mainProtoFileSources + .resolve("some.proto") + .replace("content = 1", "content = 2") + + val fourthRunMain = runGradle(bufGenerateMain) + + assertEquals(TaskOutcome.SUCCESS, fourthRunMain.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.UP_TO_DATE, fourthRunMain.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, fourthRunMain.protoTaskOutcome(generateBufGenYamlMain)) + assertEquals(TaskOutcome.SUCCESS, fourthRunMain.protoTaskOutcome(processMainProtoFiles)) + + val firstRunTest = runGradle(bufGenerateTest) + + assertEquals(TaskOutcome.SUCCESS, firstRunTest.protoTaskOutcome(bufGenerateTest)) + assertEquals(TaskOutcome.SUCCESS, firstRunTest.protoTaskOutcome(generateBufYamlTest)) + assertEquals(TaskOutcome.SUCCESS, firstRunTest.protoTaskOutcome(generateBufGenYamlTest)) + assertEquals(TaskOutcome.SUCCESS, firstRunTest.protoTaskOutcome(processTestProtoFiles)) + assertEquals(TaskOutcome.SUCCESS, firstRunTest.protoTaskOutcome(processTestImportProtoFiles)) + + assertEquals(TaskOutcome.UP_TO_DATE, firstRunTest.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.UP_TO_DATE, firstRunTest.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, firstRunTest.protoTaskOutcome(generateBufGenYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, firstRunTest.protoTaskOutcome(processMainProtoFiles)) + + val secondRunTest = runGradle(bufGenerateTest) + + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(bufGenerateTest)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(generateBufYamlTest)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(generateBufGenYamlTest)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(processTestProtoFiles)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(processTestImportProtoFiles)) + + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(generateBufGenYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, secondRunTest.protoTaskOutcome(processMainProtoFiles)) + + testProtoFileSources + .resolve("other.proto") + .replace("content = 1", "content = 2") + + val thirdRunTest = runGradle(bufGenerateTest) + + assertEquals(TaskOutcome.SUCCESS, thirdRunTest.protoTaskOutcome(bufGenerateTest)) + assertEquals(TaskOutcome.UP_TO_DATE, thirdRunTest.protoTaskOutcome(generateBufYamlTest)) + assertEquals(TaskOutcome.UP_TO_DATE, thirdRunTest.protoTaskOutcome(generateBufGenYamlTest)) + assertEquals(TaskOutcome.SUCCESS, thirdRunTest.protoTaskOutcome(processTestProtoFiles)) + assertEquals(TaskOutcome.UP_TO_DATE, thirdRunTest.protoTaskOutcome(processTestImportProtoFiles)) + + assertEquals(TaskOutcome.UP_TO_DATE, thirdRunTest.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.UP_TO_DATE, thirdRunTest.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, thirdRunTest.protoTaskOutcome(generateBufGenYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, thirdRunTest.protoTaskOutcome(processMainProtoFiles)) + + mainProtoFileSources + .resolve("some.proto") + .replace("content = 2", "content = 3") + + val fourthRunTest = runGradle(bufGenerateTest) + + assertEquals(TaskOutcome.SUCCESS, fourthRunTest.protoTaskOutcome(bufGenerateTest)) + assertEquals(TaskOutcome.UP_TO_DATE, fourthRunTest.protoTaskOutcome(generateBufYamlTest)) + assertEquals(TaskOutcome.UP_TO_DATE, fourthRunTest.protoTaskOutcome(generateBufGenYamlTest)) + assertEquals(TaskOutcome.UP_TO_DATE, fourthRunTest.protoTaskOutcome(processTestProtoFiles)) + assertEquals(TaskOutcome.SUCCESS, fourthRunTest.protoTaskOutcome(processTestImportProtoFiles)) + + assertEquals(TaskOutcome.SUCCESS, fourthRunTest.protoTaskOutcome(bufGenerateMain)) + assertEquals(TaskOutcome.UP_TO_DATE, fourthRunTest.protoTaskOutcome(generateBufYamlMain)) + assertEquals(TaskOutcome.UP_TO_DATE, fourthRunTest.protoTaskOutcome(generateBufGenYamlMain)) + assertEquals(TaskOutcome.SUCCESS, fourthRunTest.protoTaskOutcome(processMainProtoFiles)) + } } diff --git a/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcKmpProjectTest.kt b/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcKmpProjectTest.kt new file mode 100644 index 000000000..bc9836ac5 --- /dev/null +++ b/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcKmpProjectTest.kt @@ -0,0 +1,125 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc + +import kotlinx.rpc.base.GrpcBaseTest +import org.junit.jupiter.api.TestInstance +import kotlin.io.path.Path +import kotlin.test.Test + +@TestInstance(TestInstance.Lifecycle.PER_METHOD) +class GrpcKmpProjectTest : GrpcBaseTest() { + override val isKmp: Boolean = true + + @Test + fun `Minimal gRPC Configuration`() = runGrpcTest { + val result = runGradle(bufGenerateMain) + + result.assertMainTaskExecuted( + protoFiles = listOf( + Path("some.proto") + ), + generatedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ) + ) + } + + @Test + fun `No gRPC`() = runGrpcTest { + runNonExistentTask(bufGenerateMain) + runNonExistentTask(bufGenerateTest) + runNonExistentTask(processMainProtoFiles) + runNonExistentTask(processTestProtoFiles) + runNonExistentTask(processTestImportProtoFiles) + runNonExistentTask(generateBufYamlMain) + runNonExistentTask(generateBufYamlTest) + runNonExistentTask(generateBufGenYamlMain) + runNonExistentTask(generateBufGenYamlTest) + } + + @Test + fun `Test-Only Sources`() = runGrpcTest { + val result = runGradle(bufGenerateTest) + + result.assertTestTaskExecuted( + protoFiles = listOf( + Path("some.proto"), + ), + importProtoFiles = emptyList(), + generatedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ), + importGeneratedFiles = emptyList() + ) + } + + @Test + fun `Main and Test Mixed Sources`() = runGrpcTest { + val mainRun = runGradle(bufGenerateMain) + + mainRun.assertMainTaskExecuted( + protoFiles = listOf( + Path("some.proto") + ), + generatedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ) + ) + + cleanProtoBuildDir() + + val testRun = runGradle(bufGenerateTest) + + testRun.assertTestTaskExecuted( + protoFiles = listOf( + Path("other.proto") + ), + importProtoFiles = listOf( + Path("some.proto") + ), + generatedFiles = listOf( + Path("Other.kt"), + Path(RPC_INTERNAL, "Other.kt"), + ), + importGeneratedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ) + ) + } + + @Test + // todo remove after KRPC-180 + fun `No JVM Targets`() = runGrpcTest { + runNonExistentTask(bufGenerateMain) + runNonExistentTask(bufGenerateTest) + runNonExistentTask(processMainProtoFiles) + runNonExistentTask(processTestProtoFiles) + runNonExistentTask(processTestImportProtoFiles) + runNonExistentTask(generateBufYamlMain) + runNonExistentTask(generateBufYamlTest) + runNonExistentTask(generateBufGenYamlMain) + runNonExistentTask(generateBufGenYamlTest) + } + + @Test + fun `With Other Targets`() = runGrpcTest { + val result = runGradle(bufGenerateMain) + + result.assertMainTaskExecuted( + protoFiles = listOf( + Path("some.proto") + ), + generatedFiles = listOf( + Path("Some.kt"), + Path(RPC_INTERNAL, "Some.kt"), + ) + ) + } +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/can_add_custom_protoc_plugins/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/can_add_custom_protoc_plugins/build.gradle.kts new file mode 100644 index 000000000..526a93fd8 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/can_add_custom_protoc_plugins/build.gradle.kts @@ -0,0 +1,44 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version +import kotlinx.rpc.proto.* + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +rpc { + grpc { + protocPlugins { + create("myPlugin") { + local { + executor("path", "to", "protoc-gen-myplugin.exe") + } + + options.put("hello", "world") + options.put("foo", "bar") + + strategy = ProtocPlugin.Strategy.All + includeImports = true + includeWkt = false + types = listOf("my.type.Yay") + excludeTypes = listOf("my.type.Nope") + } + create("myRemotePlugin") { + remote { + locator = "my.remote.plugin" + } + } + } + } +} + +protoSourceSets { + main { + protocPlugin(rpc.grpc.protocPlugins.named("myPlugin")) + protocPlugin(rpc.grpc.protocPlugins.named("myRemotePlugin")) + } +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/build.gradle.kts new file mode 100644 index 000000000..f3e6962e7 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/build.gradle.kts @@ -0,0 +1,30 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version +import kotlinx.rpc.proto.* +import kotlinx.rpc.buf.* +import java.io.File +import kotlin.time.Duration.Companion.seconds + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +rpc { + grpc { + buf { + configFile = File("some.buf.yaml") + logFormat = BufExtension.LogFormat.Json + timeout = 60.seconds + + generate { + includeImports = true + includeWkt = true + errorFormat = BufGenerateExtension.ErrorFormat.Json + } + } + } +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/some.buf.yaml b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/some.buf.yaml new file mode 100644 index 000000000..3207dd305 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/some.buf.yaml @@ -0,0 +1 @@ +broken yaml file diff --git a/gradle-plugin/src/test/resources/projects/.keep b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/src/main/proto/some.proto similarity index 100% rename from gradle-plugin/src/test/resources/projects/.keep rename to gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_buf_cli_flags/src/main/proto/some.proto diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_protoc_plugins_must_declare_an_artifact/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_protoc_plugins_must_declare_an_artifact/build.gradle.kts new file mode 100644 index 000000000..6acb669c7 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/custom_protoc_plugins_must_declare_an_artifact/build.gradle.kts @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version +import kotlinx.rpc.proto.* + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +rpc { + grpc { + protocPlugins { + create("myPlugin") {} + } + } +} + +protoSourceSets { + main { + protocPlugin(rpc.grpc.protocPlugins.named("myPlugin")) + } +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/build.gradle.kts new file mode 100644 index 000000000..aafd2083f --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/build.gradle.kts @@ -0,0 +1,31 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +protoSourceSets { + main { + proto { + exclude("exclude/**") + exclude("exclude.proto") + } + } + + test { + proto { + include("include/**") + include("include.proto") + include("some/package/hello/world/file.proto") + } + } +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/.keep b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/exclude.proto similarity index 100% rename from gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/.keep rename to gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/exclude.proto diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/exclude/no1.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/exclude/no1.proto new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/exclude/no2.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/exclude/no2.proto new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/ok/ok.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/ok/ok.proto new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/main/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include.proto new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include/yes1.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include/yes1.proto new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include/yes2.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/include/yes2.proto new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/other.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/other.proto new file mode 100644 index 000000000..7ad86c779 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/other.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Other { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/some/package/hello/world/file.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/exclude_and_include_in_protosourcesets/src/test/proto/some/package/hello/world/file.proto new file mode 100644 index 000000000..e69de29bb diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/build.gradle.kts new file mode 100644 index 000000000..e9b01b47d --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/build.gradle.kts @@ -0,0 +1,14 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/src/main/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/src/main/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/src/main/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/src/test/proto/other.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/src/test/proto/other.proto new file mode 100644 index 000000000..7ad86c779 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/main_and_test_mixed_sources/src/test/proto/other.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Other { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/no_grpc/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/no_grpc/build.gradle.kts index cc6194819..85727fd2f 100644 --- a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/no_grpc/build.gradle.kts +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/no_grpc/build.gradle.kts @@ -8,3 +8,9 @@ plugins { kotlin("jvm") version "" id("org.jetbrains.kotlinx.rpc.plugin") } + +// should nonetheless be available +protoSourceSets { + main {} + test {} +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/build.gradle.kts new file mode 100644 index 000000000..3b6317883 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/build.gradle.kts @@ -0,0 +1,15 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version +import kotlinx.rpc.proto.kotlinMultiplatform + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/src/main/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/src/main/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/src/main/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/src/test/proto/other.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/src/test/proto/other.proto new file mode 100644 index 000000000..7ad86c779 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/proto_tasks_are_cached_properly/src/test/proto/other.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Other { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/skip_generation_when_no_proto_files/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/skip_generation_when_no_proto_files/build.gradle.kts new file mode 100644 index 000000000..4ce1593cb --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/skip_generation_when_no_proto_files/build.gradle.kts @@ -0,0 +1,23 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.internal.impldep.org.junit.experimental.categories.Categories.CategoryFilter.include +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +protoSourceSets { + main { + proto { + exclude("some.proto") + } + } +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/skip_generation_when_no_proto_files/src/main/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/skip_generation_when_no_proto_files/src/main/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/skip_generation_when_no_proto_files/src/main/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/test_only_sources/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/test_only_sources/build.gradle.kts new file mode 100644 index 000000000..e9b01b47d --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/test_only_sources/build.gradle.kts @@ -0,0 +1,14 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("jvm") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/test_only_sources/src/test/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/test_only_sources/src/test/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcJvmProjectTest/test_only_sources/src/test/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/build.gradle.kts new file mode 100644 index 000000000..cbd88cc2c --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/build.gradle.kts @@ -0,0 +1,18 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("multiplatform") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +kotlin { + jvm() +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/src/jvmMain/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/src/jvmMain/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/src/jvmMain/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/src/jvmTest/proto/other.proto b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/src/jvmTest/proto/other.proto new file mode 100644 index 000000000..7ad86c779 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/main_and_test_mixed_sources/src/jvmTest/proto/other.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Other { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/minimal_grpc_configuration/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/minimal_grpc_configuration/build.gradle.kts new file mode 100644 index 000000000..cbd88cc2c --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/minimal_grpc_configuration/build.gradle.kts @@ -0,0 +1,18 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("multiplatform") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +kotlin { + jvm() +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/minimal_grpc_configuration/src/jvmMain/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/minimal_grpc_configuration/src/jvmMain/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/minimal_grpc_configuration/src/jvmMain/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/no_grpc/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/no_grpc/build.gradle.kts new file mode 100644 index 000000000..315141d9c --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/no_grpc/build.gradle.kts @@ -0,0 +1,16 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("multiplatform") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +// should nonetheless be available +protoSourceSets { + jvmMain {} + jvmTest {} +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/no_jvm_targets/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/no_jvm_targets/build.gradle.kts new file mode 100644 index 000000000..b30e26cf5 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/no_jvm_targets/build.gradle.kts @@ -0,0 +1,21 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("multiplatform") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +kotlin { + js() + macosArm64() +} + +// should nonetheless be available +protoSourceSets { + jvmMain {} + jvmTest {} +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/test_only_sources/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/test_only_sources/build.gradle.kts new file mode 100644 index 000000000..cbd88cc2c --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/test_only_sources/build.gradle.kts @@ -0,0 +1,18 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("multiplatform") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +kotlin { + jvm() +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/test_only_sources/src/jvmTest/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/test_only_sources/src/jvmTest/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/test_only_sources/src/jvmTest/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/with_other_targets/build.gradle.kts b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/with_other_targets/build.gradle.kts new file mode 100644 index 000000000..85e4446bd --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/with_other_targets/build.gradle.kts @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +import org.gradle.kotlin.dsl.version + +plugins { + kotlin("multiplatform") version "" + id("org.jetbrains.kotlinx.rpc.plugin") +} + +kotlin { + jvm() + js() + macosArm64() +} + +protoSourceSets { + jvmMain {} + jvmTest {} +} + +rpc { + grpc() +} diff --git a/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/with_other_targets/src/jvmMain/proto/some.proto b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/with_other_targets/src/jvmMain/proto/some.proto new file mode 100644 index 000000000..9ce4a4156 --- /dev/null +++ b/gradle-plugin/src/test/resources/projects/GrpcKmpProjectTest/with_other_targets/src/jvmMain/proto/some.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; + +message Some { + string content = 1; +} From 4f5c707d48f284852586a314b9f6eb0bd98db7c6 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Tue, 29 Jul 2025 17:06:35 +0200 Subject: [PATCH 4/6] Fixed plugin issues found with tests --- .../kotlin/kotlinx/rpc/buf/BufExecutable.kt | 2 +- .../kotlinx/rpc/buf/tasks/BufExecTask.kt | 3 + .../kotlinx/rpc/buf/tasks/BufGenerateTask.kt | 5 +- .../rpc/buf/tasks/GenerateBufGenYaml.kt | 16 +++--- .../kotlinx/rpc/buf/tasks/GenerateBufYaml.kt | 19 ++++--- .../kotlinx/rpc/grpc/DefaultGrpcExtension.kt | 57 ++++++++++++------- .../rpc/proto/DefaultProtoSourceSet.kt | 10 +++- .../kotlinx/rpc/proto/ProcessProtoFiles.kt | 11 +--- .../kotlin/kotlinx/rpc/proto/ProtocPlugin.kt | 4 +- .../kotlin/kotlinx/rpc/util/ProcessRunner.kt | 2 +- 10 files changed, 71 insertions(+), 58 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/BufExecutable.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/BufExecutable.kt index fd4a9acea..bedbd3642 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/BufExecutable.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/BufExecutable.kt @@ -56,7 +56,7 @@ internal fun BufExecTask.execBuf(args: Iterable) { val configValue = configFile.orNull if (configValue != null) { add("--config") - add(configValue.absolutePath) + add(configValue.path) } if (debug.get()) { diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufExecTask.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufExecTask.kt index a321684b9..ce85238e8 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufExecTask.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufExecTask.kt @@ -27,6 +27,7 @@ import kotlinx.rpc.buf.BUF_GEN_YAML import kotlinx.rpc.buf.BUF_YAML import kotlinx.rpc.buf.BufTasksExtension import org.gradle.api.logging.LogLevel +import org.gradle.api.tasks.Classpath /** * Abstract base class for `buf` tasks. @@ -60,6 +61,8 @@ public abstract class BufExecTask : DefaultTask() { * The working directory for the `buf` command. */ @get:InputDirectory + // https://docs.gradle.org/current/userguide/incremental_build.html#sec:configure_input_normalization + @get:Classpath public abstract val workingDir: Property /** diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt index e18615a65..27f14f9ca 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt @@ -15,7 +15,6 @@ import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskProvider import java.io.File import kotlinx.rpc.buf.BufGenerateExtension -import org.gradle.api.provider.Provider import org.gradle.api.tasks.InputDirectory /** @@ -24,11 +23,11 @@ import org.gradle.api.tasks.InputDirectory * @see buf generate */ public abstract class BufGenerateTask : BufExecTask() { - // unsued, but required for Gradle to properly recognize inputs + // unsued, but required for Gradle to properly recognise inputs @get:InputDirectory internal abstract val protoFilesDir: Property - // unsued, but required for Gradle to properly recognize inputs + // unsued, but required for Gradle to properly recognise inputs @get:InputDirectory internal abstract val importFilesDir: Property diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufGenYaml.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufGenYaml.kt index 061cfe9b2..42c033386 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufGenYaml.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufGenYaml.kt @@ -26,7 +26,7 @@ internal data class ResolvedGrpcPlugin( val type: Type, val locator: List, val out: String, - val options: Map, + val options: Map, val strategy: String?, val includeImports: Boolean?, val includeWkt: Boolean?, @@ -91,6 +91,13 @@ public abstract class GenerateBufGenYaml : DefaultTask() { } writer.appendLine(" - ${plugin.type.name}: $locatorLine") + writer.appendLine(" out: ${plugin.out}") + if (plugin.options.isNotEmpty()) { + writer.appendLine(" opt:") + plugin.options.forEach { (key, value) -> + writer.appendLine(" - $key=$value") + } + } if (plugin.strategy != null) { writer.appendLine(" strategy: ${plugin.strategy}") } @@ -112,13 +119,6 @@ public abstract class GenerateBufGenYaml : DefaultTask() { writer.appendLine(" - $type") } } - writer.appendLine(" out: ${plugin.out}") - if (plugin.options.isNotEmpty()) { - writer.appendLine(" opt:") - plugin.options.forEach { (key, value) -> - writer.appendLine(" - $key${if (value != null) "=$value" else ""}") - } - } } writer.appendLine("inputs:") diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufYaml.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufYaml.kt index 2b39e4085..75e6d2859 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufYaml.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufYaml.kt @@ -11,7 +11,6 @@ import org.gradle.api.DefaultTask import org.gradle.api.Project import org.gradle.api.provider.Property import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskProvider @@ -22,11 +21,11 @@ import java.io.File * Generates/updates a Buf `buf.yaml` file. */ public abstract class GenerateBufYaml : DefaultTask() { - @get:InputDirectory - internal abstract val protoSourceDir: Property + @get:Input + internal abstract val protoSourceDir: Property - @get:InputDirectory - internal abstract val importSourceDir: Property + @get:Input + internal abstract val importSourceDir: Property @get:Input internal abstract val withImport: Property @@ -61,13 +60,15 @@ public abstract class GenerateBufYaml : DefaultTask() { writer.appendLine("modules:") - val protoDir = protoSourceDir.get() + val protoDirName = protoSourceDir.get() + val protoDir = file.parentFile.resolve(protoDirName) if (protoDir.exists()) { val modulePath = protoDir.relativeTo(file.parentFile) writer.appendLine(" - path: $modulePath") } - val importDir = importSourceDir.get() + val importDirName = importSourceDir.get() + val importDir = file.parentFile.resolve(importDirName) if (withImport.get() && importDir.exists()) { val modulePath = importDir.relativeTo(file.parentFile) writer.appendLine(" - path: $modulePath") @@ -92,8 +93,8 @@ internal fun Project.registerGenerateBufYamlTask( ): TaskProvider { val capitalizeName = name.replaceFirstChar { it.uppercase() } return tasks.register("${GenerateBufYaml.NAME_PREFIX}$capitalizeName") { - protoSourceDir.set(buildSourceSetsProtoDir) - importSourceDir.set(buildSourceSetsImportDir) + protoSourceDir.set(buildSourceSetsProtoDir.name) + importSourceDir.set(buildSourceSetsImportDir.name) this.withImport.set(withImport) val bufYamlFile = buildSourceSetsDir diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt index 9147acd3f..74ba9eaa3 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt @@ -80,6 +80,15 @@ internal open class DefaultGrpcExtension @Inject constructor( @Suppress("detekt.LongMethod", "detekt.CyclomaticComplexMethod") private fun Project.configureTasks(protoSourceSet: DefaultProtoSourceSet) { + // todo remove after KRPC-180 + if (!protoSourceSet.languageSourceSets.isPresent) { + logger.debug( + "Language source sets are not set for proto source set '${protoSourceSet.name}', skipping buf tasks configuration" + ) + + return + } + val baseName = protoSourceSet.name val buildSourceSetsDir = project.protoBuildDirSourceSets.resolve(baseName) @@ -103,30 +112,11 @@ internal open class DefaultGrpcExtension @Inject constructor( val protoFiles = protoSourceSet.proto - val generateBufYamlTask = registerGenerateBufYamlTask( - name = baseName, - buildSourceSetsDir = buildSourceSetsDir, - buildSourceSetsProtoDir = buildSourceSetsProtoDir, - buildSourceSetsImportDir = buildSourceSetsImportDir, - withImport = pairSourceSet != null, - ) - - val generateBufGenYamlTask = registerGenerateBufGenYamlTask( - name = baseName, - buildSourceSetsDir = buildSourceSetsDir, - protocPlugins = includedProtocPlugins, - ) { - dependsOn(generateBufYamlTask) - } - val processProtoTask = registerProcessProtoFilesTask( name = baseName, destination = buildSourceSetsProtoDir, protoFiles = protoFiles, - ) { - dependsOn(generateBufYamlTask) - dependsOn(generateBufGenYamlTask) - } + ) val processImportProtoTask = if (pairSourceSet != null) { val importProtoFiles = pairSourceSet.proto @@ -136,14 +126,33 @@ internal open class DefaultGrpcExtension @Inject constructor( destination = buildSourceSetsImportDir, protoFiles = importProtoFiles, ) { - dependsOn(generateBufYamlTask) - dependsOn(generateBufGenYamlTask) dependsOn(processProtoTask) } } else { null } + val generateBufYamlTask = registerGenerateBufYamlTask( + name = baseName, + buildSourceSetsDir = buildSourceSetsDir, + buildSourceSetsProtoDir = buildSourceSetsProtoDir, + buildSourceSetsImportDir = buildSourceSetsImportDir, + withImport = pairSourceSet != null, + ) { + dependsOn(processProtoTask) + if (processImportProtoTask != null) { + dependsOn(processImportProtoTask) + } + } + + val generateBufGenYamlTask = registerGenerateBufGenYamlTask( + name = baseName, + buildSourceSetsDir = buildSourceSetsDir, + protocPlugins = includedProtocPlugins, + ) { + dependsOn(generateBufYamlTask) + } + val out = protoBuildDirGenerated.resolve(baseName) val destinationFileTree = fileTree(buildSourceSetsProtoDir) @@ -281,6 +290,10 @@ internal open class DefaultGrpcExtension @Inject constructor( }) } + // ignore for bufGenerate task caching + project.normalization.runtimeClasspath.ignore("**/protoc-gen-kotlin-multiplatform.log") + project.normalization.runtimeClasspath.ignore("**/.keep") + protocPlugins.create(GRPC_JAVA) { isJava.set(true) diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/DefaultProtoSourceSet.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/DefaultProtoSourceSet.kt index 0c59d9f30..fc33bca6e 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/DefaultProtoSourceSet.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/DefaultProtoSourceSet.kt @@ -63,7 +63,7 @@ internal open class DefaultProtoSourceSet @Inject constructor( } internal fun Project.createProtoExtensions() { - fun findOrCreateAndConfigure(languageSourceSetName: String, languageSourceSet: Any) { + fun findOrCreateAndConfigure(languageSourceSetName: String, languageSourceSet: Any?) { val container = project.findOrCreate(PROTO_SOURCE_SETS) { val container = objects.domainObjectContainer( ProtoSourceSet::class.java, @@ -77,10 +77,13 @@ internal fun Project.createProtoExtensions() { val protoSourceSet = container.maybeCreate(languageSourceSetName) as DefaultProtoSourceSet - protoSourceSet.languageSourceSets.add(languageSourceSet) + languageSourceSet?.let { protoSourceSet.languageSourceSets.add(it) } } project.withKotlinJvmExtension { + findOrCreateAndConfigure("main", null) + findOrCreateAndConfigure("test", null) + sourceSets.configureEach { if (name == SourceSet.MAIN_SOURCE_SET_NAME || name == SourceSet.TEST_SOURCE_SET_NAME) { findOrCreateAndConfigure(name, this) @@ -97,6 +100,9 @@ internal fun Project.createProtoExtensions() { } project.withKotlinKmpExtension { + findOrCreateAndConfigure("jvmMain", null) + findOrCreateAndConfigure("jvmTest", null) + sourceSets.configureEach { if (name == "jvmMain" || name == "jvmTest") { findOrCreateAndConfigure(name, this) diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProcessProtoFiles.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProcessProtoFiles.kt index a00e42f0e..ed6b7e61d 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProcessProtoFiles.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProcessProtoFiles.kt @@ -4,7 +4,6 @@ package kotlinx.rpc.proto -import kotlinx.rpc.util.ensureDirectoryExists import kotlinx.rpc.util.ensureRegularFileExists import org.gradle.api.Project import org.gradle.api.file.SourceDirectorySet @@ -12,7 +11,6 @@ import org.gradle.api.tasks.Copy import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.register import java.io.File -import java.nio.file.Files /** * Copy proto files to a temporary directory for Buf to process. @@ -32,19 +30,12 @@ internal fun Project.registerProcessProtoFilesTask( val capitalName = name.replaceFirstChar { it.uppercase() } return tasks.register("process${capitalName}ProtoFiles") { - val allFiles = protoFiles.files - // this task deletes the destination directory if it results in NO-SOURCE, // which breaks the configuration cache for bufGenerate // so we prevent No-SOURCE by creating a .keep file in the destination directory val keep = protoBuildDirSourceSetsKeep.ensureRegularFileExists() from(keep) - - from(protoFiles.srcDirs) { - include { - it.file in allFiles - } - } + from(protoFiles) into(destination) diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProtocPlugin.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProtocPlugin.kt index d560c6c75..8edd61ff8 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProtocPlugin.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProtocPlugin.kt @@ -93,8 +93,8 @@ public open class ProtocPlugin( * * @see Buf documentation - opt */ - public val options: MapProperty = project.objects - .mapProperty() + public val options: MapProperty = project.objects + .mapProperty() .convention(emptyMap()) /** diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/util/ProcessRunner.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/util/ProcessRunner.kt index 97c4cd663..186e5a616 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/util/ProcessRunner.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/util/ProcessRunner.kt @@ -55,7 +55,7 @@ internal class ProcessRunner : Closeable { ) { fun formattedOutput() = buildString { appendLine("Process $name finished:") - appendLine(" - Arguments: $args") + appendLine(" - Buf Arguments: $args") appendLine(" - Exit code: $exitCode") val perStream = { name: String, content: ByteArray -> val string = content.toString(StandardCharsets.UTF_8) From b1924d289722f24a0c625ab94e53fbfcbd635624 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Tue, 29 Jul 2025 17:07:16 +0200 Subject: [PATCH 5/6] apiDump --- gradle-plugin/api/gradle-plugin.api | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/gradle-plugin/api/gradle-plugin.api b/gradle-plugin/api/gradle-plugin.api index 1c4dcb973..28ced8ae7 100644 --- a/gradle-plugin/api/gradle-plugin.api +++ b/gradle-plugin/api/gradle-plugin.api @@ -85,7 +85,12 @@ public final class kotlinx/rpc/buf/BufGenerateExtension$ErrorFormat : java/lang/ public class kotlinx/rpc/buf/BufTasksExtension { public fun (Lorg/gradle/api/Project;)V - public final fun registerWorkspaceTask (Lkotlin/reflect/KClass;Ljava/lang/String;Lorg/gradle/api/Action;)Lorg/gradle/api/provider/Provider; + public final fun registerWorkspaceTask (Lkotlin/reflect/KClass;Ljava/lang/String;Lorg/gradle/api/Action;)Lkotlinx/rpc/buf/BufTasksExtension$TaskProvider; +} + +public abstract interface class kotlinx/rpc/buf/BufTasksExtension$TaskProvider { + public abstract fun getMainTask ()Lorg/gradle/api/provider/Provider; + public abstract fun getTestTask ()Lorg/gradle/api/provider/Provider; } public final class kotlinx/rpc/buf/ConstsKt { @@ -149,7 +154,7 @@ public abstract interface class kotlinx/rpc/grpc/GrpcExtension { } public final class kotlinx/rpc/proto/ConstsKt { - public static final field KXRPC_PLUGIN_JAR_CONFIGURATION Ljava/lang/String; + public static final field PROTOC_GEN_KOTLIN_MULTIPLATFORM_JAR_CONFIGURATION Ljava/lang/String; public static final field PROTO_BUILD_DIR Ljava/lang/String; public static final field PROTO_BUILD_GENERATED Ljava/lang/String; public static final field PROTO_BUILD_SOURCE_SETS Ljava/lang/String; @@ -160,8 +165,8 @@ public final class kotlinx/rpc/proto/ConstsKt { public static final field PROTO_SOURCE_SETS Ljava/lang/String; } -public final class kotlinx/rpc/proto/KxrpcPluginJarKt { - public static final fun getKxrpcProtocPluginJarPath (Lorg/gradle/api/Project;)Lorg/gradle/api/provider/Provider; +public final class kotlinx/rpc/proto/KotlinMultiplatformPluginJarKt { + public static final fun getKotlinMultiplatformProtocPluginJarPath (Lorg/gradle/api/Project;)Lorg/gradle/api/provider/Provider; } public abstract class kotlinx/rpc/proto/ProcessProtoFiles : org/gradle/api/tasks/Copy { @@ -185,7 +190,7 @@ public class kotlinx/rpc/proto/ProtocPlugin { public static final field Companion Lkotlinx/rpc/proto/ProtocPlugin$Companion; public static final field GRPC_JAVA Ljava/lang/String; public static final field GRPC_KOTLIN Ljava/lang/String; - public static final field KXRPC Ljava/lang/String; + public static final field KOTLIN_MULTIPLATFORM Ljava/lang/String; public static final field PROTOBUF_JAVA Ljava/lang/String; public fun (Ljava/lang/String;Lorg/gradle/api/Project;)V public final fun getArtifact ()Lorg/gradle/api/provider/Property; @@ -207,6 +212,7 @@ public abstract class kotlinx/rpc/proto/ProtocPlugin$Artifact { public final class kotlinx/rpc/proto/ProtocPlugin$Artifact$Local : kotlinx/rpc/proto/ProtocPlugin$Artifact { public fun (Lorg/gradle/api/Project;)V public final fun executor (Lorg/gradle/api/provider/Provider;)V + public final fun executor ([Ljava/lang/String;)V public final fun getExecutor ()Lorg/gradle/api/provider/ListProperty; public final fun javaJar (Ljava/lang/String;)V public final fun javaJar (Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;)V @@ -231,11 +237,11 @@ public final class kotlinx/rpc/proto/ProtocPlugin$Strategy : java/lang/Enum { public final class kotlinx/rpc/proto/ProtocPluginKt { public static final fun getGrpcJava (Lorg/gradle/api/NamedDomainObjectContainer;)Lorg/gradle/api/NamedDomainObjectProvider; public static final fun getGrpcKotlin (Lorg/gradle/api/NamedDomainObjectContainer;)Lorg/gradle/api/NamedDomainObjectProvider; - public static final fun getKxrpc (Lorg/gradle/api/NamedDomainObjectContainer;)Lorg/gradle/api/NamedDomainObjectProvider; + public static final fun getKotlinMultiplatform (Lorg/gradle/api/NamedDomainObjectContainer;)Lorg/gradle/api/NamedDomainObjectProvider; public static final fun getProtobufJava (Lorg/gradle/api/NamedDomainObjectContainer;)Lorg/gradle/api/NamedDomainObjectProvider; public static final fun grpcJava (Lorg/gradle/api/NamedDomainObjectContainer;Lorg/gradle/api/Action;)V public static final fun grpcKotlin (Lorg/gradle/api/NamedDomainObjectContainer;Lorg/gradle/api/Action;)V - public static final fun kxrpc (Lorg/gradle/api/NamedDomainObjectContainer;Lorg/gradle/api/Action;)V + public static final fun kotlinMultiplatform (Lorg/gradle/api/NamedDomainObjectContainer;Lorg/gradle/api/Action;)V public static final fun protobufJava (Lorg/gradle/api/NamedDomainObjectContainer;Lorg/gradle/api/Action;)V } From 45299f264b39398a52ee1960758b696ec2cef241 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Tue, 29 Jul 2025 17:09:04 +0200 Subject: [PATCH 6/6] detekt --- .../src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt | 5 +++-- .../kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt | 3 ++- .../src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt | 1 + .../src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt index 74ba9eaa3..83db5de9b 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt @@ -78,12 +78,13 @@ internal open class DefaultGrpcExtension @Inject constructor( } } - @Suppress("detekt.LongMethod", "detekt.CyclomaticComplexMethod") + @Suppress("detekt.LongMethod", "detekt.CyclomaticComplexMethod", "detekt.ThrowsCount") private fun Project.configureTasks(protoSourceSet: DefaultProtoSourceSet) { // todo remove after KRPC-180 if (!protoSourceSet.languageSourceSets.isPresent) { logger.debug( - "Language source sets are not set for proto source set '${protoSourceSet.name}', skipping buf tasks configuration" + "Language source sets are not set for proto source set '${protoSourceSet.name}', " + + "skipping buf tasks configuration" ) return diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt index 1e3735a09..a1dcf08ac 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/kotlinMultiplatformPluginJar.kt @@ -21,7 +21,8 @@ import org.gradle.api.provider.Provider * ``` */ public val Project.kotlinMultiplatformProtocPluginJarPath: Provider - get() = project.configurations.named(PROTOC_GEN_KOTLIN_MULTIPLATFORM_JAR_CONFIGURATION).map { it.singleFile.absolutePath } + get() = project.configurations.named(PROTOC_GEN_KOTLIN_MULTIPLATFORM_JAR_CONFIGURATION) + .map { it.singleFile.absolutePath } internal fun Project.configureKotlinMultiplatformPluginJarConfiguration() { configurations.create(PROTOC_GEN_KOTLIN_MULTIPLATFORM_JAR_CONFIGURATION) diff --git a/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt b/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt index d271f1f42..5de8dd0ce 100644 --- a/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt +++ b/gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcJvmProjectTest.kt @@ -173,6 +173,7 @@ inputs: assert(result.output.contains("Artifact is not specified for protoc plugin myPlugin")) } + @Suppress("detekt.MaxLineLength") private val cliFlagsRegex = "- Buf Arguments: \\[.*?, generate, --output, .*?, --include-imports, --include-wkt, --error-format, json, --config, some\\.buf\\.yaml, --log-format, json, --timeout, 60s]".toRegex() @Test diff --git a/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt b/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt index 50c0563ab..e19263bc9 100644 --- a/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt +++ b/gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt @@ -81,7 +81,8 @@ abstract class GrpcBaseTest : BaseTest() { }.toSet() protoSources.walk().forEach { - if (it.isRegularFile() && it.extension == "proto" && it.relativeTo(protoSources).pathString !in included) { + val pathString = it.relativeTo(protoSources).pathString + if (it.isRegularFile() && it.extension == "proto" && pathString !in included) { fail("File 'file://${it.absolutePathString()}' in '$protoSources' is not expected") } }