Skip to content

Commit

Permalink
Move GradlePropertiesBuilder test util to separate class
Browse files Browse the repository at this point in the history
Moving GradlePropertiesBuilder to a separate class will permit reusing it in Dokka integration tests that will be introduced in PR #3904
  • Loading branch information
adam-enko committed Nov 5, 2024
1 parent 8dba7bb commit e4b59f3
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 129 deletions.
Original file line number Diff line number Diff line change
@@ -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<String, String> = 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)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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<String, String> = 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -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.
Expand Down

0 comments on commit e4b59f3

Please sign in to comment.