diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/PluginFeaturesService.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/PluginFeaturesService.kt index 5f7fc0a434..c83f64630f 100644 --- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/PluginFeaturesService.kt +++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/PluginFeaturesService.kt @@ -13,6 +13,8 @@ import org.gradle.api.provider.Provider import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters import org.gradle.kotlin.dsl.extra +import org.gradle.kotlin.dsl.provideDelegate +import org.jetbrains.dokka.gradle.internal.PluginFeaturesService.PluginMode.* import java.io.File import java.util.* @@ -25,62 +27,111 @@ import java.util.* internal abstract class PluginFeaturesService : BuildService { interface Params : BuildServiceParameters { - /** @see PluginFeaturesService.v2PluginEnabled */ - val v2PluginEnabled: Property - - /** @see [PluginFeaturesService.v2PluginNoWarn] */ - val v2PluginNoWarn: Property - - /** @see [PluginFeaturesService.v2PluginMigrationHelpersEnabled] */ - val v2PluginMigrationHelpersEnabled: Property - /** @see [PluginFeaturesService.primaryService] */ val primaryService: Property + /** @see PluginFeaturesService.pluginMode */ + val pluginMode: Property + + /** If `true`, suppress [pluginMode] messages. */ + val pluginModeNoWarn: Property + /** If `true`, enable K2 analysis. */ val k2AnalysisEnabled: Property - /** If `true`, suppress the K2 analysis message. */ + /** If `true`, suppress [k2AnalysisEnabled] messages. */ val k2AnalysisNoWarn: Property + + /** [Project.getDisplayName] - only used for log messages. */ + val projectDisplayName: Property + + /** [Project.getProjectDir] - only used for log messages. */ + val projectDirectory: Property } /** * Designate this [BuildService] as 'primary', meaning it should log messages to users. * Non-primary services should not log messages. * - * Why? Because Gradle is buggy. Sometimes registering a BuildService fails. - * See https://github.com/gradle/gradle/issues/17559. - * If service registration fails then re-register the service, but with a distinct name - * (so it doesn't clash with the existing but inaccessible BuildService), and don't mark it as 'primary'. + * Why? Two reasons: + * + * 1. Sometimes registering a BuildService fails. + * See https://github.com/gradle/gradle/issues/17559. + * If service registration fails then re-register the service, but with a distinct name + * (so it doesn't clash with the existing but inaccessible BuildService), + * and don't mark it as 'primary' to avoid duplicate logging. + * 2. The method Gradle uses to generates accessors for pre-compiled script plugins + * (see [PluginFeaturesService.Companion.configureParamsDuringAccessorsGeneration]) + * runs in a temporary project that is evaluated twice. * * @see org.jetbrains.dokka.gradle.internal.registerIfAbsent */ - private val primaryService: Boolean get() = parameters.primaryService.getOrElse(false) + private val primaryService: Boolean + get() = parameters.primaryService.getOrElse(false) /** * Whether DGP should use V2 [org.jetbrains.dokka.gradle.DokkaBasePlugin]. * - * Otherwise, fallback to V1 [org.jetbrains.dokka.gradle.DokkaClassicPlugin]. + * @see pluginMode */ internal val v2PluginEnabled: Boolean by lazy { - val v2PluginEnabled = parameters.v2PluginEnabled.getOrElse(false) + when (pluginMode) { + V1Enabled, + -> false - if (v2PluginEnabled) { - logV2PluginMessage() - } else { - logV1PluginMessage() + V2EnabledWithHelpers, + V2Enabled, + -> true } + } + + /** + * Enable some migration helpers to aid in migrating DGP from V1 to V2. + * + * @see addV2MigrationHelpers + */ + internal val v2PluginMigrationHelpersEnabled: Boolean by lazy { + pluginMode == V2EnabledWithHelpers + } + + /** + * Determines the behaviour of DGP. + * + * If no valid value is detected then use [PluginMode.Default]. + */ + private val pluginMode: PluginMode by lazy { + val parameterValue = parameters.pluginMode.getOrElse(PluginMode.Default.name) + + val value = PluginMode.findOrNull(parameterValue) + ?: run { + logger.warn("Invalid value for $PLUGIN_MODE_FLAG. Got '$parameterValue' but expected one of: ${PluginMode.values.map { it.name }}") + PluginMode.Default + } + + logger.info { "Dokka Gradle Plugin detected PluginMode:$value (from:$parameterValue) in ${parameters.projectDisplayName.orNull} ${parameters.projectDirectory.orNull}" } + + logPluginMessage(value) - v2PluginEnabled + value } - /** If `true`, suppress any messages regarding V2 mode. */ - private val v2PluginNoWarn: Boolean - get() = parameters.v2PluginNoWarn.getOrElse(false) + private val pluginModeNoWarn: Boolean by lazy { + parameters.pluginModeNoWarn.getOrElse(false) + } + private fun logPluginMessage(mode: PluginMode) { + when (mode) { + V1Enabled, + -> logV1PluginMessage() + + V2Enabled, + V2EnabledWithHelpers, + -> logV2PluginMessage() + } + } private fun logV1PluginMessage() { - if (primaryService) { + if (primaryService && !pluginModeNoWarn) { logger.warn( """ |⚠ Warning: Dokka Gradle Plugin V1 mode is enabled @@ -92,7 +143,7 @@ internal abstract class PluginFeaturesService : BuildService = values().toSet() + + fun findOrNull(value: String): PluginMode? = + values.find { it.name == value } + } } companion object { private val logger = Logging.getLogger(PluginFeaturesService::class.java) - /** @see [PluginFeaturesService.v2PluginEnabled] */ - internal const val V2_PLUGIN_ENABLED_FLAG = - "org.jetbrains.dokka.experimental.gradlePlugin.enableV2" + /** @see [PluginFeaturesService.pluginMode] */ + private const val PLUGIN_MODE_FLAG = + "org.jetbrains.dokka.experimental.gradle.pluginMode" - /** @see [PluginFeaturesService.v2PluginNoWarn] */ - internal const val V2_PLUGIN_NO_WARN_FLAG = - "$V2_PLUGIN_ENABLED_FLAG.nowarn" + /** @see [PluginFeaturesService.pluginModeNoWarn] */ + private const val PLUGIN_MODE_NO_WARN_FLAG = + "$PLUGIN_MODE_FLAG.nowarn" - /** The same as [V2_PLUGIN_NO_WARN_FLAG], but it doesn't trigger spell-checks. */ - private const val V2_PLUGIN_NO_WARN_FLAG_PRETTY = - "$V2_PLUGIN_ENABLED_FLAG.noWarn" - - private const val V2_PLUGIN_MIGRATION_HELPERS_FLAG = - "org.jetbrains.dokka.experimental.gradlePlugin.enableV2MigrationHelpers" + /** The same as [PLUGIN_MODE_NO_WARN_FLAG], but it doesn't trigger spell-checks. */ + private const val PLUGIN_MODE_NO_WARN_FLAG_PRETTY = + "$PLUGIN_MODE_FLAG.noWarn" private const val K2_ANALYSIS_ENABLED_FLAG = "org.jetbrains.dokka.experimental.tryK2" @@ -234,7 +291,7 @@ internal abstract class PluginFeaturesService : BuildService { /** Find a flag for [PluginFeaturesService]. */ - fun getFlag(flag: String): Provider = + fun getFlag(flag: String): Provider = project.providers .gradleProperty(flag) .forUseAtConfigurationTimeCompat() @@ -246,17 +303,23 @@ internal abstract class PluginFeaturesService : BuildService Provider.forUseAtConfigurationTimeCompat(): Provider = } else { this } + +/** + * Convert a String Provider to a Boolean Provider. + * + * @see String.toBoolean + */ +internal fun Provider.toBoolean(): Provider = + map(String::toBoolean) diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/logUtils.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/logUtils.kt index d974ea39fd..305799851d 100644 --- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/logUtils.kt +++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/logUtils.kt @@ -9,3 +9,8 @@ import org.gradle.api.logging.Logger internal fun Logger.warn(msg: () -> String) { if (isWarnEnabled) warn(msg()) } + +/** Only evaluate and log [msg] when [Logger.isInfoEnabled] is `true`. */ +internal fun Logger.info(msg: () -> String) { + if (isInfoEnabled) warn(msg()) +} diff --git a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleProjectUtils.kt b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleProjectUtils.kt index 20f0762def..3dc5f57710 100644 --- a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleProjectUtils.kt +++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleProjectUtils.kt @@ -4,13 +4,11 @@ package org.jetbrains.dokka.gradle.utils import org.gradle.api.Project -import org.jetbrains.dokka.gradle.internal.PluginFeaturesService.Companion.V2_PLUGIN_ENABLED_FLAG -import org.jetbrains.dokka.gradle.internal.PluginFeaturesService.Companion.V2_PLUGIN_NO_WARN_FLAG fun Project.enableV2Plugin( suppressV2Message: Boolean = true ): Project { - extensions.extraProperties.set(V2_PLUGIN_ENABLED_FLAG, true) - extensions.extraProperties.set(V2_PLUGIN_NO_WARN_FLAG, suppressV2Message) + extensions.extraProperties.set("org.jetbrains.dokka.experimental.gradle.pluginMode", "V2Enabled") + extensions.extraProperties.set("org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn", suppressV2Message) return this } 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 59e1beb308..566bd63c5d 100644 --- a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleTestKitUtils.kt +++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/GradleTestKitUtils.kt @@ -86,9 +86,9 @@ class GradleProjectTest( /** Dokka specific options. */ data class DokkaArgs( - var v2Plugin: Boolean? = true, - var v2PluginNoWarn: Boolean? = v2Plugin, - var v2MigrationHelpers: Boolean? = null, + /** @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, @@ -122,9 +122,8 @@ class GradleProjectTest( } with(dokka) { - putNotNull("org.jetbrains.dokka.experimental.gradlePlugin.enableV2", v2Plugin) - putNotNull("org.jetbrains.dokka.experimental.gradlePlugin.enableV2.noWarn", v2PluginNoWarn) - putNotNull("org.jetbrains.dokka.experimental.gradlePlugin.enableV2MigrationHelpers", v2MigrationHelpers) + 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) @@ -163,7 +162,7 @@ class GradleProjectTest( val runner: GradleRunner get() = GradleRunner.create() .withProjectDir(projectDir.toFile()) - .updateGradleProperties(gradleProperties) + .writeGradleProperties(gradleProperties) companion object { val dokkaVersionOverride: String? by optionalSystemProperty() 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 30cc76010b..5b084da2a0 100644 --- a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/gradleRunnerUtils.kt +++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/gradleRunnerUtils.kt @@ -6,7 +6,6 @@ package org.jetbrains.dokka.gradle.utils import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.BuildTask import org.gradle.testkit.runner.GradleRunner -import java.util.* import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -35,7 +34,10 @@ inline fun GradleRunner.buildAndFail( ): Unit = buildAndFail().let(handleResult) -fun GradleRunner.updateGradleProperties( +/** + * Create, or overwrite, the `gradle.properties` file in [GradleRunner.getProjectDir]. + */ +fun GradleRunner.writeGradleProperties( arguments: GradleProjectTest.GradleProperties, ): GradleRunner { val gradlePropertiesFile = projectDir.resolve("gradle.properties").apply { @@ -45,13 +47,10 @@ fun GradleRunner.updateGradleProperties( } } - val gradleProperties = Properties().apply { - load(gradlePropertiesFile.inputStream()) - }.entries.associate { it.key.toString() to it.value.toString() }.toMutableMap() + val gradleProperties = arguments.toGradleProperties() - arguments.toGradleProperties().forEach { (k, v) -> - gradleProperties[k] = v - } + // Avoid using java.util.Properties because it produces non-deterministic output (e.g. a timestamp), + // which negatively impacts caching. gradlePropertiesFile.writeText( gradleProperties diff --git a/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/projects/NoConfigMultiModuleProject.kt b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/projects/NoConfigMultiModuleProject.kt new file mode 100644 index 0000000000..6d30843323 --- /dev/null +++ b/dokka-runners/dokka-gradle-plugin/src/testFixtures/kotlin/projects/NoConfigMultiModuleProject.kt @@ -0,0 +1,111 @@ +/* + * 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.projects + +import io.kotest.core.test.TestScope +import org.jetbrains.dokka.gradle.internal.DokkaConstants +import org.jetbrains.dokka.gradle.utils.* + +/** + * A simple multi-module project with no configuration + * (so that it can be used in both DGPv1 and v2 modes). + * + * It's a multi-module project, and each subproject has slightly different Gradle plugins + * to try and trigger Gradle classloader bugs so ensure that DGP can handle them. + */ +fun TestScope.initNoConfigMultiModuleProject( + testName: String = testCase.name.testName, + rootProjectName: String? = null, + config: GradleProjectTest.() -> Unit = {}, +): GradleProjectTest { + + // get the FQN of the class that contains the test, so even though multiple + // tests uses this project it's unlikely that the project dirs clash + val baseDirName = testCase.descriptor.ids().first().value + .substringAfter("org.jetbrains.dokka.gradle.") // drop the package name + .replaceNonAlphaNumeric() + + return gradleKtsProjectTest( + projectLocation = "$baseDirName/multi-module-hello-goodbye/$testName", + rootProjectName = rootProjectName, + ) { + + gradleProperties { + dokka { + pluginMode = null + } + } + + settingsGradleKts += """ + | + |include(":subproject-one") + |include(":subproject-two") + | + """.trimMargin() + + buildGradleKts = """ + |plugins { + | kotlin("jvm") version embeddedKotlinVersion apply false + | // important: don't register Dokka in the root project, because we _want_ the test to trigger a + | // Gradle classloader bug. + | //id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" + |} + | + """.trimMargin() + + dir("subproject-one") { + buildGradleKts = """ + |plugins { + | kotlin("jvm") version embeddedKotlinVersion + | // important: Register different plugins here to make the buildscript classpath different, + | // because we _want_ the test to trigger a Gradle classloader bug. + | kotlin("plugin.serialization") version embeddedKotlinVersion + | id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" + |} + | + """.trimMargin() + + createKotlinFile( + "src/main/kotlin/One.kt", + """ + |package com.project.one + | + |/** `One` class */ + |class One { + | /** prints `One` to the console */ + | fun sayName() = println("One") + |} + | + """.trimMargin() + ) + } + + dir("subproject-two") { + + buildGradleKts = """ + |plugins { + | kotlin("jvm") version embeddedKotlinVersion + | id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" + |} + | + """.trimMargin() + + createKotlinFile( + "src/main/kotlin/Two.kt", + """ + |package com.project.two + | + |/** `Two` class */ + |class Two { + | /** prints `Two` to the console */ + | fun sayName() = println("Two") + |} + | + """.trimMargin() + ) + } + + config() + } +} diff --git a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/BuildSrcKotlinDslAccessorsTest.kt b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/BuildSrcKotlinDslAccessorsTest.kt deleted file mode 100644 index 3e3371d2c8..0000000000 --- a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/BuildSrcKotlinDslAccessorsTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 - -import io.kotest.core.spec.style.FunSpec -import org.gradle.testkit.runner.TaskOutcome.* -import org.jetbrains.dokka.gradle.internal.DokkaConstants -import org.jetbrains.dokka.gradle.utils.* - -class BuildSrcKotlinDslAccessorsTest : FunSpec({ - - val project = initProjectWithBuildSrcConvention() - - context("when DGPv2 is enabled") { - project - .runner - .addArguments( - ":compileKotlin", - "--project-dir", "buildSrc", - ) - .build { - test("expect DGPv2 can be used in a convention plugin") { - shouldHaveTasksWithAnyOutcome(":compileKotlin" to listOf(SUCCESS, UP_TO_DATE, FROM_CACHE)) - } - } - } -}) - -private fun initProjectWithBuildSrcConvention( - rootProjectName: String? = null, - config: GradleProjectTest.() -> Unit = {}, -): GradleProjectTest { - - return gradleKtsProjectTest( - projectLocation = "BuildSrcKotlinDslAccessorsTest", - rootProjectName = rootProjectName, - ) { - - buildGradleKts = """ - |plugins { - | kotlin("jvm") version embeddedKotlinVersion - | id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" - |} - | - """.trimMargin() - - dir("buildSrc") { - buildGradleKts = """ - |plugins { - | `kotlin-dsl` - |} - | - |dependencies { - | implementation("org.jetbrains.dokka:dokka-gradle-plugin:${DokkaConstants.DOKKA_VERSION}") - |} - | - """.trimMargin() - - - settingsGradleKts = """ - |rootProject.name = "buildSrc" - | - |${settingsRepositories()} - | - """.trimMargin() - - createFile( - "src/main/kotlin/dokka-convention.gradle.kts", - /* language=TEXT */ """ - |plugins { - | id("org.jetbrains.dokka") - |} - | - |dokka { - | moduleName.set("custom-module-name") - |} - | - """.trimMargin() - ) - } - - gradleProperties { - dokka { - v2Plugin = true - v2MigrationHelpers = true - } - } - - config() - } -} diff --git a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/KotlinDslAccessorsTest.kt b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/KotlinDslAccessorsTest.kt index 770cb7dc88..32398beca3 100644 --- a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/KotlinDslAccessorsTest.kt +++ b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/KotlinDslAccessorsTest.kt @@ -25,14 +25,7 @@ import kotlin.test.assertEquals class KotlinDslAccessorsTest : FunSpec({ context("Kotlin DSL generated accessors") { - val project = initMultiModuleProject("KotlinDslAccessorsTest") { - gradleProperties { - dokka { - v2Plugin = false - v2MigrationHelpers = false - } - } - } + val project = initMultiModuleProject("KotlinDslAccessorsTest") /** * Verify the current accessors match the dumped accessors. @@ -208,23 +201,27 @@ private fun GradleProjectTest.generateDokkaV2MigrationHelpersAccessors( } /** - * Generate Kotlin DSL Accessors by running `:` in [projectPath]. + * Generate Kotlin DSL Accessors by running `:kotlinDslAccessorsReport` in [projectPath]. * * @returns Dokka-specific accessors, and a file of all accessors (to be used in assertion failure messages.) */ private fun GradleProjectTest.generateDokkaAccessors( projectPath: String, - enableV2MigrationHelpers: Boolean? = null, + enableV2MigrationHelpers: Boolean = false, ): GeneratedDokkaAccessors { + + gradleProperties { + dokka { + pluginMode = if (enableV2MigrationHelpers) "V2EnabledWithHelpers" else "V2Enabled" + pluginModeNoWarn = true + } + } + runner .addArguments( buildList { add(org.gradle.util.Path.path(projectPath).relativePath("kotlinDslAccessorsReport").toString()) add("--quiet") - add("-Porg.jetbrains.dokka.experimental.gradlePlugin.enableV2=true") - enableV2MigrationHelpers?.let { - add("-Porg.jetbrains.dokka.experimental.gradlePlugin.enableV2MigrationHelpers=$it") - } } ) .build { diff --git a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/MigrationMessagesTest.kt b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/MigrationMessagesTest.kt index dc1a144063..61df6232a9 100644 --- a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/MigrationMessagesTest.kt +++ b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/MigrationMessagesTest.kt @@ -7,13 +7,24 @@ import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.string.shouldContainOnlyOnce import io.kotest.matchers.string.shouldNotContain import org.gradle.testkit.runner.BuildResult -import org.jetbrains.dokka.gradle.internal.DokkaConstants -import org.jetbrains.dokka.gradle.utils.* +import org.jetbrains.dokka.gradle.utils.addArguments +import org.jetbrains.dokka.gradle.utils.build +import org.jetbrains.dokka.gradle.utils.projects.initNoConfigMultiModuleProject +import org.jetbrains.dokka.gradle.utils.shouldNotContainAnyOf class MigrationMessagesTest : FunSpec({ context("given multi-module project") { - val project = migrationMessagesTestProject() + val project = initNoConfigMultiModuleProject { + gradleProperties { + // Disable the automatic config of these options, so we can control them + // manually with command line flags in the tests. + dokka { + pluginMode = null + pluginModeNoWarn = null + } + } + } context("when no plugin flags are set") { project.runner @@ -30,13 +41,13 @@ class MigrationMessagesTest : FunSpec({ } } - context("when v2 is disabled") { + context("when v1 is enabled") { project.runner .addArguments( ":help", "--dry-run", "--warn", - "-P$V2_PLUGIN_ENABLED_FLAG=false", + "-P$PLUGIN_MODE_FLAG=V1Enabled", ) .addArguments() .build { @@ -48,61 +59,69 @@ class MigrationMessagesTest : FunSpec({ context("when v2 is enabled") { - project.runner - .addArguments( - ":help", - "--dry-run", - "-P$V2_PLUGIN_ENABLED_FLAG=true", - ) - .build { - test("output should only contain V2 message") { - shouldOnlyContainV2Message() - } - } - listOf( - V2_PLUGIN_NO_WARN_FLAG, - V2_PLUGIN_NO_WARN_FLAG_PRETTY, - ).forEach { noWarnFlag -> - context("and message is suppressed with $noWarnFlag") { + "$PLUGIN_MODE_FLAG=V2Enabled", + "$PLUGIN_MODE_FLAG=V2EnabledWithHelpers", + ).forEach { v2EnabledFlag -> + + context("with flag $v2EnabledFlag") { project.runner .addArguments( ":help", "--dry-run", - "-P$V2_PLUGIN_ENABLED_FLAG=true", - "-P$noWarnFlag=true", + "-P$v2EnabledFlag", ) .build { - test("output should not contain any Dokka plugin message") { - output.shouldNotContainAnyOf( - "Dokka Gradle Plugin V1", - "Dokka Gradle Plugin V2", - "https://kotl.in/dokka-gradle-migration", - "https://github.com/Kotlin/dokka/issues/", - "org.jetbrains.dokka.experimental.gradlePlugin", - V2_PLUGIN_ENABLED_FLAG, - V2_PLUGIN_NO_WARN_FLAG, - V2_PLUGIN_NO_WARN_FLAG_PRETTY, - noWarnFlag, - ) + test("output should only contain V2 message") { + shouldOnlyContainV2Message() } } } + + listOf( + "$PLUGIN_MODE_NO_WARN_FLAG=true", + "$PLUGIN_MODE_NO_WARN_FLAG_PRETTY=true", + ).forEach { noWarnFlag -> + context("and message is suppressed with $noWarnFlag") { + project.runner + .addArguments( + ":help", + "--dry-run", + "-P$v2EnabledFlag", + "-P$noWarnFlag", + ) + .build { + test("output should not contain any Dokka plugin message") { + output.shouldNotContainAnyOf( + "Dokka Gradle Plugin V1", + "Dokka Gradle Plugin V2", + "https://kotl.in/dokka-gradle-migration", + "https://github.com/Kotlin/dokka/issues/", + "org.jetbrains.dokka.experimental.gradlePlugin", + PLUGIN_MODE_FLAG, + PLUGIN_MODE_NO_WARN_FLAG, + PLUGIN_MODE_NO_WARN_FLAG_PRETTY, + noWarnFlag, + ) + } + } + } + } } } } }) { companion object { - private const val V2_PLUGIN_ENABLED_FLAG = - "org.jetbrains.dokka.experimental.gradlePlugin.enableV2" + private const val PLUGIN_MODE_FLAG = + "org.jetbrains.dokka.experimental.gradle.pluginMode" - private const val V2_PLUGIN_NO_WARN_FLAG = - "${V2_PLUGIN_ENABLED_FLAG}.nowarn" + private const val PLUGIN_MODE_NO_WARN_FLAG = + "org.jetbrains.dokka.experimental.gradle.pluginMode.nowarn" - private const val V2_PLUGIN_NO_WARN_FLAG_PRETTY = - "${V2_PLUGIN_ENABLED_FLAG}.noWarn" + private const val PLUGIN_MODE_NO_WARN_FLAG_PRETTY = + "org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn" - fun BuildResult.shouldOnlyContainV1Warning() { + private fun BuildResult.shouldOnlyContainV1Warning() { output shouldContainOnlyOnce /* language=text */ """ |┌──────────────────────────────────────────────────────────────────────────────────────┐ |│ ⚠ Warning: Dokka Gradle Plugin V1 mode is enabled │ @@ -114,7 +133,7 @@ class MigrationMessagesTest : FunSpec({ |│ https://kotl.in/dokka-gradle-migration │ |│ │ |│ Once you have prepared your project, enable V2 by adding │ - |│ org.jetbrains.dokka.experimental.gradlePlugin.enableV2=true │ + |│ org.jetbrains.dokka.experimental.gradle.pluginMode=V2EnabledWithHelpers │ |│ to your project's `gradle.properties` │ |│ │ |│ Please report any feedback or problems to Dokka GitHub Issues │ @@ -124,117 +143,24 @@ class MigrationMessagesTest : FunSpec({ output shouldNotContain "Dokka Gradle Plugin V2" } - fun BuildResult.shouldOnlyContainV2Message() { + private fun BuildResult.shouldOnlyContainV2Message() { output shouldContainOnlyOnce /* language=text */ """ - |┌──────────────────────────────────────────────────────────────────────────┐ - |│ Dokka Gradle Plugin V2 is enabled ♡ │ - |│ │ - |│ We would appreciate your feedback! │ - |│ Please report any feedback or problems to Dokka GitHub Issues │ - |│ https://github.com/Kotlin/dokka/issues/ │ - |│ │ - |│ If you need help or advice, check out the migration guide │ - |│ https://kotl.in/dokka-gradle-migration │ - |│ │ - |│ You can suppress this message by adding │ - |│ org.jetbrains.dokka.experimental.gradlePlugin.enableV2.nowarn=true │ - |│ to your project's `gradle.properties` │ - |└──────────────────────────────────────────────────────────────────────────┘ + |┌──────────────────────────────────────────────────────────────────────┐ + |│ Dokka Gradle Plugin V2 is enabled ♡ │ + |│ │ + |│ We would appreciate your feedback! │ + |│ Please report any feedback or problems to Dokka GitHub Issues │ + |│ https://github.com/Kotlin/dokka/issues/ │ + |│ │ + |│ If you need help or advice, check out the migration guide │ + |│ https://kotl.in/dokka-gradle-migration │ + |│ │ + |│ You can suppress this message by adding │ + |│ org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true │ + |│ to your project's `gradle.properties` │ + |└──────────────────────────────────────────────────────────────────────┘ """.trimMargin() output shouldNotContain "Dokka Gradle Plugin V1" } - - } -} - - -/** - * A simple multi-module project with no configuration (so that it can be used with both Dokka V1 and V2 plugins). - * - * It's a multi-module project to verify that even though there are multiple subprojects only one message is logged. - */ -private fun migrationMessagesTestProject( - config: GradleProjectTest.() -> Unit = {}, -): GradleProjectTest { - - return gradleKtsProjectTest("MigrationMessagesTest") { - - gradleProperties { - dokka { - v2Plugin = null - v2PluginNoWarn = null - } - } - - settingsGradleKts += """ - | - |include(":subproject-one") - |include(":subproject-two") - | - """.trimMargin() - - buildGradleKts = """ - |plugins { - | kotlin("jvm") version embeddedKotlinVersion apply false - | // important: don't register Dokka in the root project, because we _want_ the test to trigger a - | // Gradle classloader bug. - | //id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" - |} - | - """.trimMargin() - - dir("subproject-one") { - buildGradleKts = """ - |plugins { - | kotlin("jvm") version embeddedKotlinVersion - | // important: Register different plugins here to make the buildscript classpath different, - | // because we _want_ the test to trigger a Gradle classloader bug. - | kotlin("plugin.serialization") version embeddedKotlinVersion - | id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" - |} - | - """.trimMargin() - - createKotlinFile( - "src/main/kotlin/One.kt", - """ - |package com.project.one - | - |/** `One` class */ - |class One { - | /** prints `One` to the console */ - | fun sayName() = println("One") - |} - | - """.trimMargin() - ) - } - - dir("subproject-two") { - - buildGradleKts = """ - |plugins { - | kotlin("jvm") version embeddedKotlinVersion - | id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" - |} - | - """.trimMargin() - - createKotlinFile( - "src/main/kotlin/Two.kt", - """ - |package com.project.two - | - |/** `Two` class */ - |class Two { - | /** prints `Two` to the console */ - | fun sayName() = println("Two") - |} - | - """.trimMargin() - ) - } - - config() } } diff --git a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/PluginFeaturesServiceTest.kt b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/PluginFeaturesServiceTest.kt new file mode 100644 index 0000000000..f123040f1c --- /dev/null +++ b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/PluginFeaturesServiceTest.kt @@ -0,0 +1,32 @@ +/* + * 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 + +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.string.shouldContain +import org.jetbrains.dokka.gradle.utils.addArguments +import org.jetbrains.dokka.gradle.utils.build +import org.jetbrains.dokka.gradle.utils.projects.initNoConfigMultiModuleProject + +class PluginFeaturesServiceTest : FunSpec({ + context("given multi-module project") { + val project = initNoConfigMultiModuleProject() + + context("when PluginMode has invalid value") { + project.runner + .addArguments( + ":help", + "--dry-run", + "--warn", + "-Porg.jetbrains.dokka.experimental.gradle.pluginMode=blah", + ) + .addArguments() + .build { + test("output should contain V1 warning") { + output shouldContain "Invalid value for org.jetbrains.dokka.experimental.gradle.pluginMode. Got 'blah' but expected one of: [V1Enabled, V2EnabledWithHelpers, V2Enabled]" + } + } + } + } +})