From 7e225cd83975f2eba23875107be2547d2099a026 Mon Sep 17 00:00:00 2001 From: Adam Semenenko <152864218+adam-enko@users.noreply.github.com> Date: Mon, 21 Oct 2024 13:14:13 +0200 Subject: [PATCH] Fix HTML link in composite builds Log using the root-most Gradle project, taking composite builds into account. --- .../main/kotlin/formats/DokkaHtmlPlugin.kt | 7 +- .../src/main/kotlin/internal/gradleUtils.kt | 20 +-- .../tasks/LogHtmlPublicationLinkTaskTest.kt | 141 +++++++++++++++--- 3 files changed, 126 insertions(+), 42 deletions(-) diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/formats/DokkaHtmlPlugin.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/formats/DokkaHtmlPlugin.kt index ec4cda1ca6..5f4c557a0a 100644 --- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/formats/DokkaHtmlPlugin.kt +++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/formats/DokkaHtmlPlugin.kt @@ -16,7 +16,7 @@ import org.jetbrains.dokka.gradle.engine.plugins.DokkaHtmlPluginParameters.Compa import org.jetbrains.dokka.gradle.engine.plugins.DokkaVersioningPluginParameters import org.jetbrains.dokka.gradle.engine.plugins.DokkaVersioningPluginParameters.Companion.DOKKA_VERSIONING_PLUGIN_PARAMETERS_NAME import org.jetbrains.dokka.gradle.internal.DokkaInternalApi -import org.jetbrains.dokka.gradle.internal.rootProjectName +import org.jetbrains.dokka.gradle.internal.rootGradle import org.jetbrains.dokka.gradle.internal.uppercaseFirstChar import org.jetbrains.dokka.gradle.tasks.DokkaGeneratePublicationTask import org.jetbrains.dokka.gradle.tasks.LogHtmlPublicationLinkTask @@ -72,8 +72,9 @@ constructor( .flatMap { it.outputDirectory.file("index.html") } val indexHtmlPath = indexHtmlFile.map { indexHtml -> - val rootProjectName = project.rootProjectName() - val relativePath = indexHtml.asFile.relativeTo(project.rootDir) + val rootProjectName = project.rootGradle().rootProject.name + val rootProjectDir = project.rootGradle().rootProject.projectDir + val relativePath = indexHtml.asFile.relativeTo(rootProjectDir) "${rootProjectName}/${relativePath.invariantSeparatorsPath}" } diff --git a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/gradleUtils.kt b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/gradleUtils.kt index 3375e0189e..66a1cd3d9f 100644 --- a/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/gradleUtils.kt +++ b/dokka-runners/dokka-gradle-plugin/src/main/kotlin/internal/gradleUtils.kt @@ -12,6 +12,7 @@ import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.AttributeContainer import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.invocation.Gradle import org.gradle.api.model.ObjectFactory import org.gradle.api.plugins.ExtensionAware import org.gradle.api.plugins.ExtensionContainer @@ -370,20 +371,9 @@ internal const val INTERNAL_CONF_DESCRIPTION_TAG = "[Internal Dokka Configuratio /** - * Get the root project name. + * Get the root-most [Gradle] instance. * - * This function will try to be compatible with - * [Isolated Projects](https://docs.gradle.org/current/userguide/isolated_projects.html). + * This is useful for determining the root directory of Composite Builds. */ -internal fun Project.rootProjectName(): String { - return when { - CurrentGradleVersion >= "8.8" -> { - @Suppress("UnstableApiUsage") - isolated.rootProject.name - } - - else -> { - rootProject.name - } - } -} +internal fun Project.rootGradle(): Gradle = + generateSequence(gradle) { it.parent }.last() diff --git a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/tasks/LogHtmlPublicationLinkTaskTest.kt b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/tasks/LogHtmlPublicationLinkTaskTest.kt index a8dec5f4a4..3062a6c85e 100644 --- a/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/tasks/LogHtmlPublicationLinkTaskTest.kt +++ b/dokka-runners/dokka-gradle-plugin/src/testFunctional/kotlin/tasks/LogHtmlPublicationLinkTaskTest.kt @@ -12,16 +12,22 @@ import org.gradle.testkit.runner.TaskOutcome.SKIPPED import org.gradle.testkit.runner.TaskOutcome.SUCCESS import org.jetbrains.dokka.gradle.internal.DokkaConstants import org.jetbrains.dokka.gradle.utils.* +import kotlin.io.path.appendLines +import kotlin.io.path.copyTo class LogHtmlPublicationLinkTaskTest : FunSpec({ + // Re-run all leaves, to ensure each test has a fresh server. + //isolationMode = InstancePerLeaf + context("given an active file-host server") { val server = embeddedServer(CIO, port = 0) { } + afterSpec { server.stop(gracePeriodMillis = 0, timeoutMillis = 0) } server.start(wait = false) val serverPort = server.resolvedConnectors().first().port val validServerUri = "http://localhost:$serverPort" - val validServerUriParam = `-P`("testServerUri=$validServerUri") + val validServerUriParam = "testServerUri=$validServerUri" context("and a Kotlin project") { val project = initDokkaProject() @@ -32,10 +38,8 @@ class LogHtmlPublicationLinkTaskTest : FunSpec({ "clean", "dokkaGeneratePublicationHtml", "--stacktrace", - "--info", - validServerUriParam, + "-P${validServerUriParam}", ) - .forwardOutput() .build { test("expect project builds successfully") { output shouldContain "BUILD SUCCESSFUL" @@ -52,19 +56,15 @@ class LogHtmlPublicationLinkTaskTest : FunSpec({ } context("and the server is down") { - // stop the server immediately - server.stop(gracePeriodMillis = 0, timeoutMillis = 0) - + val invalidServerUriParam = "testServerUri=http://notavailable.test:" context("when running the generate task") { project.runner .addArguments( "clean", "dokkaGeneratePublicationHtml", "--stacktrace", - "--info", - validServerUriParam, + "-P${invalidServerUriParam}", ) - .forwardOutput() .build { test("expect project builds successfully") { output shouldContain "BUILD SUCCESSFUL" @@ -82,18 +82,46 @@ class LogHtmlPublicationLinkTaskTest : FunSpec({ } } } + + context("and a composite build project") { + val project = initCompositeBuildDokkaProject() + + val nestedProjectGradleProperties = project.file("nested-project/gradle.properties") + project.file("gradle.properties") + .copyTo( + target = nestedProjectGradleProperties, + overwrite = true, + ) + nestedProjectGradleProperties.appendLines( + listOf( + validServerUriParam + ) + ) + + context("when generate task is run with correct server URI") { + project.runner + .addArguments( + "clean", + "dokkaGenerate", + "--stacktrace", + ) + .build { + test("expect project builds successfully") { + output shouldContain "BUILD SUCCESSFUL" + } + test("LogHtmlPublicationLinkTask should run") { + shouldHaveTasksWithAnyOutcome( + ":nested-project:logLinkDokkaGeneratePublicationHtml" to listOf(SUCCESS) + ) + } + test("expect link is logged") { + output shouldContain "Generated Dokka HTML publication: $validServerUri/Composite%20Build%20Demo/nested-project/build/dokka/html/index.html" + } + } + } + } } -}) { - companion object { - @Suppress("SpellCheckingInspection") - /** - * prefix [param] with `-P`. - * - * (this exists to avoid annoying typo warnings, e.g. `-Pserver=localhost` -> `Typo: In word 'Pserver'`) - */ - private fun `-P`(param: String): String = "-P$param" - } -} +}) private fun initDokkaProject( @@ -106,9 +134,6 @@ private fun initDokkaProject( | id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" |} | - |dependencies { - |} - | |tasks.withType().configureEach { | serverUri.set(providers.gradleProperty("testServerUri")) |} @@ -134,3 +159,71 @@ private fun initDokkaProject( config() } } + + +private fun initCompositeBuildDokkaProject( + config: GradleProjectTest.() -> Unit = {}, +): GradleProjectTest { + return gradleKtsProjectTest( + projectLocation = "log-html-publication-link-task-composite-build", + rootProjectName = "Composite Build Demo" + ) { + buildGradleKts = """ + |plugins { + | base + |} + | + |tasks.clean { + | dependsOn(gradle.includedBuild("nested-project").task(":clean")) + |} + | + |val dokkaGenerate by tasks.registering { + | dependsOn(gradle.includedBuild("nested-project").task(":dokkaGenerate")) + |} + | + """.trimMargin() + + settingsGradleKts += """ + |includeBuild("nested-project") + """.trimMargin() + + dir("nested-project") { + buildGradleKts = """ + |plugins { + | kotlin("jvm") version "1.9.25" + | id("org.jetbrains.dokka") version "${DokkaConstants.DOKKA_VERSION}" + |} + | + |tasks.withType().configureEach { + | serverUri.set(providers.gradleProperty("testServerUri")) + |} + """.trimMargin() + + settingsGradleKts = """ + |rootProject.name = "Nested Project" + | + |${settingsRepositories()} + | + """.trimMargin() + + createKotlinFile( + "src/main/kotlin/Hello.kt", + """ + |package com.project.hello + | + |/** The Hello class */ + |class Hello { + | /** prints `Hello` to the console */ + | fun sayHello() = println("Hello") + |} + | + """.trimMargin() + ) + } + + // remove the flag that disables the logging task, since this test wants the logger to run + gradleProperties.dokka.enableLogHtmlPublicationLink = null + + config() + } +}