From e4b59f3abf1c31a375c9331c5cfe79af597d4180 Mon Sep 17 00:00:00 2001 From: Adam Semenenko <152864218+adam-enko@users.noreply.github.com> Date: Tue, 5 Nov 2024 16:02:07 +0100 Subject: [PATCH] Move GradlePropertiesBuilder test util to separate class Moving GradlePropertiesBuilder to a separate class will permit reusing it in Dokka integration tests that will be introduced in PR #3904 --- .../kotlin/GradlePropertiesBuilder.kt | 128 ++++++++++++++++++ .../testFixtures/kotlin/GradleTestKitUtils.kt | 128 +----------------- .../testFixtures/kotlin/gradleRunnerUtils.kt | 11 +- 3 files changed, 138 insertions(+), 129 deletions(-) create mode 100644 dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt diff --git a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt new file mode 100644 index 0000000000..d0797cf796 --- /dev/null +++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradlePropertiesBuilder.kt @@ -0,0 +1,128 @@ +/* +* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. +*/ +package org.jetbrains.dokka.gradle.utils + +import org.gradle.api.logging.LogLevel +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +/** + * The arguments in this class will be used to build the project's + * `gradle.properties` file. + */ +data class GradlePropertiesBuilder( + val gradle: GradleArgs = GradleArgs(), + val dokka: DokkaArgs = DokkaArgs(), + val kotlin: KotlinArgs = KotlinArgs(), +) { + fun dokka(config: DokkaArgs.() -> Unit): Unit = dokka.config() + fun gradle(config: GradleArgs.() -> Unit): Unit = gradle.config() + fun kotlin(config: KotlinArgs.() -> Unit): Unit = kotlin.config() + + /** Gradle specific options. */ + data class GradleArgs( + var logLevel: LogLevel? = LogLevel.LIFECYCLE, + var stacktrace: Boolean? = true, + var debug: Boolean? = null, + var buildCache: Boolean? = true, + var buildCacheDebugLog: Boolean? = null, + var configurationCache: Boolean? = null, + var configureOnDemand: Boolean? = null, + var continueOnFailure: Boolean? = null, + var parallel: Boolean? = null, + var warningMode: org.gradle.api.logging.configuration.WarningMode? = null, + /** Will be enabled by default in Gradle 9.0 */ + var kotlinDslSkipMetadataVersionCheck: Boolean? = true, + var daemonIdleTimeout: Duration? = 30.seconds, + /** + * Specifies the scheduling priority for the Gradle daemon and all processes launched by it. + */ + var daemonSchedulingPriority: SchedulingPriority? = SchedulingPriority.Low, + var maxWorkers: Int? = null, + val jvmArgs: JvmArgs = JvmArgs(), + + // Maybe also implement these flags? Although there's no suitable tests for them at present. + // org.gradle.projectcachedir=(directory) + // org.gradle.unsafe.isolated-projects=(true,false) + // org.gradle.vfs.verbose=(true,false) + // org.gradle.vfs.watch=(true,false) + ) { + enum class SchedulingPriority { Low, Normal } + + fun jvm(config: JvmArgs.() -> Unit): Unit = jvmArgs.config() + } + + /** Kotlin specific options. */ + data class KotlinArgs( + var mppStabilityWarning: Boolean? = true, + ) + + /** Dokka specific options. */ + data class DokkaArgs( + /** @see org.jetbrains.dokka.gradle.internal.PluginFeaturesService.PluginMode */ + var pluginMode: String? = "V2Enabled", + var pluginModeNoWarn: Boolean? = true, + var k2Analysis: Boolean? = null, + var k2AnalysisNoWarn: Boolean? = null, + var enableLogHtmlPublicationLink: Boolean? = false, + ) + + /** Gradle Daemon JVM args. */ + data class JvmArgs( + @Suppress("PropertyName") + var Xmx: String? = null, + var fileEncoding: String? = "UTF-8", + var maxMetaspaceSize: String? = "512m", + /** Enable `AlwaysPreTouch` by default https://github.com/gradle/gradle/issues/3093#issuecomment-387259298 */ + var alwaysPreTouch: Boolean = true, + ) { + fun buildString(): String = buildList { + fun addNotNull(key: String, value: String?) { + value?.let { add("$key$it") } + } + + addNotNull("-Xmx", Xmx) + addNotNull("-XX:MaxMetaspaceSize=", maxMetaspaceSize) + addNotNull("-Dfile.encoding=", fileEncoding) + if (alwaysPreTouch) add("-XX:+AlwaysPreTouch") + }.joinToString(" ") + } + + fun build(): Map = buildMap { + fun putNotNull(key: String, value: Any?) { + value?.let { put(key, value.toString()) } + } + + with(dokka) { + putNotNull("org.jetbrains.dokka.experimental.gradle.pluginMode", pluginMode) + putNotNull("org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn", pluginModeNoWarn) + putNotNull("org.jetbrains.dokka.experimental.tryK2", k2Analysis) + putNotNull("org.jetbrains.dokka.experimental.tryK2.noWarn", k2AnalysisNoWarn) + putNotNull("org.jetbrains.dokka.gradle.enableLogHtmlPublicationLink", enableLogHtmlPublicationLink) + } + + with(kotlin) { + putNotNull("kotlin.mpp.stability.nowarn", mppStabilityWarning?.let { !it }) + } + + with(gradle) { + putNotNull("org.gradle.caching", buildCache) + putNotNull("org.gradle.caching.debug", buildCacheDebugLog) + putNotNull("org.gradle.configuration-cache", configurationCache) + putNotNull("org.gradle.configureondemand", configureOnDemand) + putNotNull("org.gradle.continue", continueOnFailure) + putNotNull("org.gradle.daemon.idletimeout", daemonIdleTimeout?.inWholeMilliseconds) + putNotNull("org.gradle.priority", daemonSchedulingPriority?.name?.lowercase()) + putNotNull("org.gradle.debug", debug) + putNotNull("org.gradle.logging.level", logLevel?.name?.lowercase()) + putNotNull("org.gradle.workers.max", maxWorkers) + putNotNull("org.gradle.parallel", parallel) + putNotNull("org.gradle.stacktrace", stacktrace) + putNotNull("org.gradle.warning.mode", warningMode) + jvmArgs.buildString().takeIf { it.isNotBlank() }?.let { + put("org.gradle.jvmargs", it) + } + } + } +} diff --git a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleTestKitUtils.kt b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleTestKitUtils.kt index cfdc9b2cf6..2590c4c809 100644 --- a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleTestKitUtils.kt +++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleTestKitUtils.kt @@ -3,7 +3,6 @@ */ package org.jetbrains.dokka.gradle.utils -import org.gradle.api.logging.LogLevel import org.gradle.testkit.runner.GradleRunner import org.intellij.lang.annotations.Language import org.jetbrains.dokka.gradle.utils.GradleProjectTest.Companion.settingsRepositories @@ -14,8 +13,6 @@ import kotlin.io.path.* import kotlin.properties.PropertyDelegateProvider import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds // utils for testing using Gradle TestKit @@ -25,133 +22,12 @@ class GradleProjectTest( override val projectDir: Path, ) : ProjectDirectoryScope { - val gradleProperties = GradleProperties() + val gradleProperties = GradlePropertiesBuilder() - fun gradleProperties(config: GradleProperties.() -> Unit) { + fun gradleProperties(config: GradlePropertiesBuilder.() -> Unit) { gradleProperties.config() } - /** - * The arguments in this class will be used to build the project's - * `gradle.properties` file. - */ - data class GradleProperties( - val gradle: GradleArgs = GradleArgs(), - val dokka: DokkaArgs = DokkaArgs(), - val kotlin: KotlinArgs = KotlinArgs(), - ) { - fun dokka(config: DokkaArgs.() -> Unit): Unit = dokka.config() - fun gradle(config: GradleArgs.() -> Unit): Unit = gradle.config() - fun kotlin(config: KotlinArgs.() -> Unit): Unit = kotlin.config() - - /** Gradle specific options. */ - data class GradleArgs( - var logLevel: LogLevel? = LogLevel.LIFECYCLE, - var stacktrace: Boolean? = true, - var debug: Boolean? = null, - var buildCache: Boolean? = true, - var buildCacheDebugLog: Boolean? = null, - var configurationCache: Boolean? = null, - var configureOnDemand: Boolean? = null, - var continueOnFailure: Boolean? = null, - var parallel: Boolean? = null, - var warningMode: org.gradle.api.logging.configuration.WarningMode? = null, - /** Will be enabled by default in Gradle 9.0 */ - var kotlinDslSkipMetadataVersionCheck: Boolean? = true, - var daemonIdleTimeout: Duration? = 30.seconds, - /** - * Specifies the scheduling priority for the Gradle daemon and all processes launched by it. - * - * Valid values are `low` and `normal`, or set as `null` to set no value. - */ - var daemonSchedulingPriority: String? = "low", - var maxWorkers: Int? = null, - val jvmArgs: JvmArgs = JvmArgs(), - - // Maybe also implement these flags? Although there's no suitable tests for them at present. - // org.gradle.projectcachedir=(directory) - // org.gradle.unsafe.isolated-projects=(true,false) - // org.gradle.vfs.verbose=(true,false) - // org.gradle.vfs.watch=(true,false) - ) { - fun jvm(config: JvmArgs.() -> Unit): Unit = jvmArgs.config() - } - - /** Kotlin specific options. */ - data class KotlinArgs( - var mppStabilityWarning: Boolean? = true, - ) - - /** Dokka specific options. */ - data class DokkaArgs( - /** @see org.jetbrains.dokka.gradle.internal.PluginFeaturesService.PluginMode */ - var pluginMode: String? = "V2Enabled", - var pluginModeNoWarn: Boolean? = true, - var k2Analysis: Boolean? = null, - var k2AnalysisNoWarn: Boolean? = null, - var enableLogHtmlPublicationLink: Boolean? = false, - ) - - /** Gradle Daemon JVM args. */ - data class JvmArgs( - @Suppress("PropertyName") - var Xmx: String? = null, - var fileEncoding: String? = "UTF-8", - var maxMetaspaceSize: String? = "512m", - /** Enable `AlwaysPreTouch` by default https://github.com/gradle/gradle/issues/3093#issuecomment-387259298 */ - var alwaysPreTouch: Boolean = true, - ) { - fun buildString(): String = buildList { - fun addNotNull(key: String, value: String?) { - value?.let { add("$key$it") } - } - - addNotNull("-Xmx", Xmx) - addNotNull("-XX:MaxMetaspaceSize=", maxMetaspaceSize) - addNotNull("-Dfile.encoding=", fileEncoding) - if (alwaysPreTouch) add("-XX:+AlwaysPreTouch") - }.joinToString(" ") - } - - - internal fun toGradleProperties(): Map = buildMap { - fun putNotNull(key: String, value: Any?) { - value?.let { put(key, value.toString()) } - } - - with(dokka) { - putNotNull("org.jetbrains.dokka.experimental.gradle.pluginMode", pluginMode) - putNotNull("org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn", pluginModeNoWarn) - putNotNull("org.jetbrains.dokka.experimental.tryK2", k2Analysis) - putNotNull("org.jetbrains.dokka.experimental.tryK2.noWarn", k2AnalysisNoWarn) - putNotNull("org.jetbrains.dokka.gradle.enableLogHtmlPublicationLink", enableLogHtmlPublicationLink) - } - - with(kotlin) { - putNotNull("kotlin.mpp.stability.nowarn", mppStabilityWarning?.let { !it }) - } - - with(gradle) { - putNotNull("org.gradle.caching", buildCache) - putNotNull("org.gradle.caching.debug", buildCacheDebugLog) - putNotNull("org.gradle.configuration-cache", configurationCache) - putNotNull("org.gradle.configureondemand", configureOnDemand) - putNotNull("org.gradle.continue", continueOnFailure) - putNotNull("org.gradle.daemon.idletimeout", daemonIdleTimeout?.inWholeMilliseconds) - putNotNull("org.gradle.priority", daemonSchedulingPriority) - putNotNull("org.gradle.debug", debug) - putNotNull("org.gradle.logging.level", logLevel?.name?.lowercase()) - putNotNull("org.gradle.workers.max", maxWorkers) - putNotNull("org.gradle.parallel", parallel) - putNotNull("org.gradle.stacktrace", stacktrace) - putNotNull("org.gradle.warning.mode", warningMode) - jvmArgs.buildString().takeIf { it.isNotBlank() }?.let { - put("org.gradle.jvmargs", it) - } - } - } - } - constructor( testProjectName: String, baseDir: Path = funcTestTempDir, diff --git a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/gradleRunnerUtils.kt b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/gradleRunnerUtils.kt index 5b084da2a0..1bcfaf3372 100644 --- a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/gradleRunnerUtils.kt +++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/gradleRunnerUtils.kt @@ -29,16 +29,21 @@ inline fun GradleRunner.build( } + +@OptIn(ExperimentalContracts::class) inline fun GradleRunner.buildAndFail( handleResult: BuildResult.() -> Unit -): Unit = buildAndFail().let(handleResult) +) { + contract { callsInPlace(handleResult, InvocationKind.EXACTLY_ONCE) } + buildAndFail().let(handleResult) +} /** * Create, or overwrite, the `gradle.properties` file in [GradleRunner.getProjectDir]. */ fun GradleRunner.writeGradleProperties( - arguments: GradleProjectTest.GradleProperties, + arguments: GradlePropertiesBuilder, ): GradleRunner { val gradlePropertiesFile = projectDir.resolve("gradle.properties").apply { if (!exists()) { @@ -47,7 +52,7 @@ fun GradleRunner.writeGradleProperties( } } - val gradleProperties = arguments.toGradleProperties() + val gradleProperties = arguments.build() // Avoid using java.util.Properties because it produces non-deterministic output (e.g. a timestamp), // which negatively impacts caching.