From 2ae68b3a681a15b580f92209c556e07b1da7313a Mon Sep 17 00:00:00 2001 From: Konstantin Aksenov Date: Mon, 5 Aug 2024 19:53:38 +1000 Subject: [PATCH] feat(core): basic ci integration --- .../marathon/config/CIConfiguration.kt | 20 +++++++++++++++++++ .../marathon/config/Configuration.kt | 10 ++++++++-- .../progress/PoolProgressAccumulator.kt | 3 +++ .../malinskiy/marathon/integrations/ci/CI.kt | 5 +++++ .../integrations/ci/CIIntegrationFactory.kt | 18 +++++++++++++++++ .../marathon/integrations/ci/None.kt | 5 +++++ .../marathon/integrations/ci/Teamcity.kt | 9 +++++++++ 7 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 configuration/src/main/kotlin/com/malinskiy/marathon/config/CIConfiguration.kt create mode 100644 core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/CI.kt create mode 100644 core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/CIIntegrationFactory.kt create mode 100644 core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/None.kt create mode 100644 core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/Teamcity.kt diff --git a/configuration/src/main/kotlin/com/malinskiy/marathon/config/CIConfiguration.kt b/configuration/src/main/kotlin/com/malinskiy/marathon/config/CIConfiguration.kt new file mode 100644 index 000000000..1f10532d4 --- /dev/null +++ b/configuration/src/main/kotlin/com/malinskiy/marathon/config/CIConfiguration.kt @@ -0,0 +1,20 @@ +package com.malinskiy.marathon.config + +import com.fasterxml.jackson.annotation.JsonSubTypes +import com.fasterxml.jackson.annotation.JsonTypeInfo + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "type" +) +@JsonSubTypes( + JsonSubTypes.Type(value = CIConfiguration.Auto::class, name = "auto"), + JsonSubTypes.Type(value = CIConfiguration.None::class, name = "none"), + JsonSubTypes.Type(value = CIConfiguration.Teamcity::class, name = "teamcity"), +) +sealed class CIConfiguration { + object Auto : CIConfiguration() + object None : CIConfiguration() + object Teamcity : CIConfiguration() +} diff --git a/configuration/src/main/kotlin/com/malinskiy/marathon/config/Configuration.kt b/configuration/src/main/kotlin/com/malinskiy/marathon/config/Configuration.kt index a9db8075d..2bcb21dcf 100644 --- a/configuration/src/main/kotlin/com/malinskiy/marathon/config/Configuration.kt +++ b/configuration/src/main/kotlin/com/malinskiy/marathon/config/Configuration.kt @@ -50,6 +50,7 @@ data class Configuration private constructor( val analyticsTracking: Boolean, val bugsnagReporting: Boolean, val deviceInitializationTimeoutMillis: Long, + val ciConfiguration: CIConfiguration, ) { fun toMap() = mapOf( @@ -74,7 +75,8 @@ data class Configuration private constructor( "debug" to debug.toString(), "screenRecordingPolicy" to screenRecordingPolicy.toString(), "vendorConfiguration" to vendorConfiguration.toString(), - "deviceInitializationTimeoutMillis" to deviceInitializationTimeoutMillis.toString() + "deviceInitializationTimeoutMillis" to deviceInitializationTimeoutMillis.toString(), + "ciConfiguration" to ciConfiguration.toString(), ) override fun equals(other: Any?): Boolean { @@ -108,6 +110,7 @@ data class Configuration private constructor( if (analyticsTracking != other.analyticsTracking) return false if (bugsnagReporting != other.bugsnagReporting) return false if (deviceInitializationTimeoutMillis != other.deviceInitializationTimeoutMillis) return false + if (ciConfiguration != other.ciConfiguration) return false return true } @@ -138,6 +141,7 @@ data class Configuration private constructor( result = 31 * result + analyticsTracking.hashCode() result = 31 * result + bugsnagReporting.hashCode() result = 31 * result + deviceInitializationTimeoutMillis.hashCode() + result = 31 * result + ciConfiguration.hashCode() return result } @@ -173,6 +177,7 @@ data class Configuration private constructor( var outputConfiguration: OutputConfiguration = OutputConfiguration(), var vendorConfiguration: VendorConfiguration = VendorConfiguration.EmptyVendorConfiguration(), + var ciConfiguration: CIConfiguration = CIConfiguration.None, ) { fun build(): Configuration { return Configuration( @@ -200,7 +205,8 @@ data class Configuration private constructor( vendorConfiguration = vendorConfiguration, analyticsTracking = analyticsTracking, bugsnagReporting = bugsnagReporting, - deviceInitializationTimeoutMillis = deviceInitializationTimeoutMillis + deviceInitializationTimeoutMillis = deviceInitializationTimeoutMillis, + ciConfiguration = ciConfiguration, ) } } diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/progress/PoolProgressAccumulator.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/progress/PoolProgressAccumulator.kt index 0f39d565d..e84d7d1eb 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/progress/PoolProgressAccumulator.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/progress/PoolProgressAccumulator.kt @@ -12,6 +12,7 @@ import com.malinskiy.marathon.execution.TestStatus import com.malinskiy.marathon.execution.queue.TestAction import com.malinskiy.marathon.execution.queue.TestEvent import com.malinskiy.marathon.execution.queue.TestState +import com.malinskiy.marathon.integrations.ci.CIIntegrationFactory import com.malinskiy.marathon.log.MarathonLogging import com.malinskiy.marathon.test.Test import com.malinskiy.marathon.test.toTestName @@ -26,6 +27,7 @@ class PoolProgressAccumulator( private val tests: HashMap = HashMap() private val logger = MarathonLogging.logger {} private val executionStrategy = configuration.executionStrategy + private val ci = CIIntegrationFactory.get(configuration) private fun createState(initialCount: Int) = StateMachine.create { initialState(TestState.Added(initialCount)) @@ -265,6 +267,7 @@ class PoolProgressAccumulator( fun testStarted(device: DeviceInfo, test: Test) { transition(test, TestEvent.Started) + ci.setBuildProgress(progress().toInt()) println("${toPercent(progress())} | [${poolId.name}]-[${device.serialNumber}] ${test.toTestName()} started") } diff --git a/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/CI.kt b/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/CI.kt new file mode 100644 index 000000000..9688d74ae --- /dev/null +++ b/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/CI.kt @@ -0,0 +1,5 @@ +package com.malinskiy.marathon.integrations.ci + +interface CI { + fun setBuildProgress(int: Int) +} diff --git a/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/CIIntegrationFactory.kt b/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/CIIntegrationFactory.kt new file mode 100644 index 000000000..9b77f27d8 --- /dev/null +++ b/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/CIIntegrationFactory.kt @@ -0,0 +1,18 @@ +package com.malinskiy.marathon.integrations.ci + +import com.malinskiy.marathon.config.CIConfiguration +import com.malinskiy.marathon.config.Configuration + +object CIIntegrationFactory { + fun get(configuration: Configuration) = when (configuration.ciConfiguration) { + CIConfiguration.Auto -> auto() + CIConfiguration.None -> None + CIConfiguration.Teamcity -> Teamcity + } + + private fun auto() = when { + // Teamcity predefined variables: https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#84e0b866 + System.getenv().containsValue("TEAMCITY_VERSION") -> Teamcity + else -> None + } +} diff --git a/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/None.kt b/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/None.kt new file mode 100644 index 000000000..ea79c04cd --- /dev/null +++ b/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/None.kt @@ -0,0 +1,5 @@ +package com.malinskiy.marathon.integrations.ci + +object None: CI { + override fun setBuildProgress(int: Int) = Unit +} diff --git a/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/Teamcity.kt b/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/Teamcity.kt new file mode 100644 index 000000000..34c1c2926 --- /dev/null +++ b/core/src/main/kotlin/com/malinskiy/marathon/integrations/ci/Teamcity.kt @@ -0,0 +1,9 @@ +package com.malinskiy.marathon.integrations.ci + +object Teamcity: CI { + private fun setBuildMessage(message: String) = println("##teamcity[buildStatus text='$message']") + + private fun setKeyValue(key: String, value: String) = println("##teamcity[buildStatisticValue key='$key' value='$value']") + + override fun setBuildProgress(int: Int) = setBuildMessage("Marathon run: $int %") +}