From 6bc0fe121a62112221e6c372a0741dc26d9fa8a5 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Tue, 10 Dec 2019 15:34:18 +0700 Subject: [PATCH] Gradle: Escape TC service messages in debug logs The MPP plugin uses TC service messages to interact with JS and native test runs an writes received messages to a debug log. But if a build is executed by TeamCity, these log messages may be treated by TC as actual service messages. This patch transforms the logged messages to avoid this issue. --- .../jetbrains/kotlin/gradle/NewMultiplatformIT.kt | 2 +- .../new-mpp-native-tests/gradle.properties | 2 ++ .../internal/testing/TCServiceMessagesClient.kt | 15 +++++++++++++-- .../testing/TCServiceMessagesTestExecutor.kt | 4 ++++ .../targets/js/testing/karma/KotlinKarma.kt | 4 +++- .../targets/js/testing/mocha/KotlinMocha.kt | 4 +++- .../targets/native/tasks/KotlinNativeTest.kt | 4 +++- 7 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index 8e8b272091a..b72fc6174b4 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -1293,7 +1293,7 @@ class NewMultiplatformIT : BaseGradleIT() { } @Test - fun testNativeTests() = with(Project("new-mpp-native-tests", gradleVersion, minLogLevel = LogLevel.INFO)) { + fun testNativeTests() = with(Project("new-mpp-native-tests", gradleVersion)) { val testTasks = listOf("macos64Test", "linux64Test", "mingw64Test", "iosTest") val hostTestTask = "${nativeHostTargetName}Test" diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-tests/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-tests/gradle.properties index 1c0ad1195e2..761d28f701d 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-tests/gradle.properties +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-native-tests/gradle.properties @@ -1 +1,3 @@ +# Enable escaping TC service messages in logs. +teamcity=true kotlin.native.disableCompilerDaemon=true \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/testing/TCServiceMessagesClient.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/testing/TCServiceMessagesClient.kt index b0ee68426b3..5136ff6eee4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/testing/TCServiceMessagesClient.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/testing/TCServiceMessagesClient.kt @@ -25,7 +25,8 @@ data class TCServiceMessagesClientSettings( val treatFailedTestOutputAsStacktrace: Boolean = false, val stackTraceParser: (String) -> ParsedStackTrace? = { null }, val ignoreOutOfRootNodes: Boolean = false, - val ignoreLineEndingAfterMessage: Boolean = true + val ignoreLineEndingAfterMessage: Boolean = true, + val escapeTCMessagesInLog: Boolean = false ) internal open class TCServiceMessagesClient( @@ -51,7 +52,17 @@ internal open class TCServiceMessagesClient( } override fun serviceMessage(message: ServiceMessage) { - log.kotlinDebug { "TCSM: $message" } + + // If a user uses TeamCity, this log may be treated by TC as an actual service message. + // So, escape logged messages if the corresponding setting is specified. + log.kotlinDebug { + val messageString = if (settings.escapeTCMessagesInLog) { + message.toString().replaceFirst("^##teamcity\\[".toRegex(), "##TC[") + } else { + message.toString() + } + "TCSM: $messageString" + } when (message) { is TestSuiteStarted -> open(message.ts, SuiteNode(requireLeafGroup(), getSuiteName(message))) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/testing/TCServiceMessagesTestExecutor.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/testing/TCServiceMessagesTestExecutor.kt index 1f34cd969b7..2999ee66746 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/testing/TCServiceMessagesTestExecutor.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/testing/TCServiceMessagesTestExecutor.kt @@ -81,4 +81,8 @@ class TCServiceMessagesTestExecutor( execHandle?.abort() outputReaderThread?.join() } + + companion object { + const val TC_PROJECT_PROPERTY = "teamcity" + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt index a52859899e7..663fb13af7a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt @@ -14,6 +14,7 @@ import org.gradle.process.ProcessForkOptions import org.jetbrains.kotlin.gradle.internal.operation import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec +import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutor.Companion.TC_PROJECT_PROPERTY import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.NpmPackageVersion import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency @@ -313,7 +314,8 @@ class KotlinKarma(override val compilation: KotlinJsCompilation) : KotlinJsTestF testNameSuffix = task.targetName, prependSuiteName = true, stackTraceParser = ::parseNodeJsStackTraceAsJvm, - ignoreOutOfRootNodes = true + ignoreOutOfRootNodes = true, + escapeTCMessagesInLog = project.hasProperty(TC_PROJECT_PROPERTY) ) config.basePath = npmProject.nodeModulesDir.absolutePath diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt index 44175ac5fe4..1a51998b9b1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt @@ -9,6 +9,7 @@ import org.gradle.api.Project import org.gradle.process.ProcessForkOptions import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec +import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutor.Companion.TC_PROJECT_PROPERTY import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.KotlinGradleNpmPackage import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency @@ -50,7 +51,8 @@ class KotlinMocha(override val compilation: KotlinJsCompilation) : KotlinJsTestF testNameSuffix = task.targetName, prependSuiteName = true, stackTraceParser = ::parseNodeJsStackTraceAsJvm, - ignoreOutOfRootNodes = true + ignoreOutOfRootNodes = true, + escapeTCMessagesInLog = project.hasProperty(TC_PROJECT_PROPERTY) ) val npmProject = compilation.npmProject diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt index ee5a0abd821..486958bec73 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt @@ -17,6 +17,7 @@ import org.gradle.process.internal.DefaultProcessForkOptions import org.jetbrains.kotlin.compilerRunner.konanVersion import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec +import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutor.Companion.TC_PROJECT_PROPERTY import org.jetbrains.kotlin.gradle.targets.native.internal.parseKotlinNativeStackTraceAsJvm import org.jetbrains.kotlin.gradle.tasks.KotlinTest import org.jetbrains.kotlin.konan.CompilerVersion @@ -117,7 +118,8 @@ abstract class KotlinNativeTest : KotlinTest() { testNameSuffix = targetName, prependSuiteName = targetName != null, treatFailedTestOutputAsStacktrace = false, - stackTraceParser = ::parseKotlinNativeStackTraceAsJvm + stackTraceParser = ::parseKotlinNativeStackTraceAsJvm, + escapeTCMessagesInLog = project.hasProperty(TC_PROJECT_PROPERTY) ) // The KotlinTest expects that the exit code is zero even if some tests failed.