Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reintroduce multimodule documentation #1804

Merged
merged 1 commit into from Mar 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions core/src/main/kotlin/configuration.kt
Expand Up @@ -100,6 +100,7 @@ interface DokkaConfiguration : Serializable {
val pluginsConfiguration: List<PluginConfiguration>
val delayTemplateSubstitution: Boolean
val suppressObviousFunctions: Boolean
val includes: Set<File>

enum class SerializationFormat : Serializable {
JSON, XML
Expand Down
1 change: 1 addition & 0 deletions core/src/main/kotlin/defaultConfiguration.kt
Expand Up @@ -17,6 +17,7 @@ data class DokkaConfigurationImpl(
override val failOnWarning: Boolean = DokkaDefaults.failOnWarning,
override val delayTemplateSubstitution: Boolean = false,
override val suppressObviousFunctions: Boolean = DokkaDefaults.suppressObviousFunctions,
override val includes: Set<File> = emptySet(),
) : DokkaConfiguration

data class PluginConfigurationImpl(
Expand Down
Expand Up @@ -35,6 +35,7 @@ class TestDokkaConfigurationBuilder {
var failOnWarning: Boolean = false
var modules: List<DokkaModuleDescriptionImpl> = emptyList()
var suppressObviousFunctions: Boolean = DokkaDefaults.suppressObviousFunctions
var includes: List<File> = emptyList()
private val lazySourceSets = mutableListOf<Lazy<DokkaSourceSetImpl>>()

fun build() = DokkaConfigurationImpl(
Expand All @@ -48,7 +49,8 @@ class TestDokkaConfigurationBuilder {
pluginsConfiguration = pluginsConfigurations,
modules = modules,
failOnWarning = failOnWarning,
suppressObviousFunctions = suppressObviousFunctions
suppressObviousFunctions = suppressObviousFunctions,
includes = includes.toSet(),
)

fun sourceSets(block: SourceSetsBuilder.() -> Unit) {
Expand Down
3 changes: 3 additions & 0 deletions docs/src/doc/docs/user_guide/gradle/usage.md
Expand Up @@ -209,6 +209,9 @@ kotlin { // Kotlin Multiplatform plugin configuration
tasks.withType<DokkaTask>().configureEach {
// custom output directory
outputDirectory.set(buildDir.resolve("dokka"))

// path to project documentation to display on all modules page
includes.from(listOf(file("project_description.md")))

dokkaSourceSets {
named("customNameMain") { // The same name as in Kotlin Multiplatform plugin, so the sources are fetched automatically
Expand Down
1 change: 1 addition & 0 deletions plugins/all-modules-page/build.gradle.kts
Expand Up @@ -12,6 +12,7 @@ dependencies {
testImplementation(project(":plugins:base:base-test-utils"))
testImplementation(project(":plugins:gfm"))
testImplementation(project(":plugins:gfm:gfm-template-processing"))
testImplementation(project(":core:content-matcher-test-utils"))

val coroutines_version: String by project
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
Expand Down
14 changes: 14 additions & 0 deletions plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt
Expand Up @@ -3,6 +3,7 @@ package org.jetbrains.dokka.allModulesPage
import org.jetbrains.dokka.DokkaConfiguration.DokkaModuleDescription
import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.parsers.MarkdownParser
import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module
import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationParsingContext
import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentation
Expand All @@ -26,6 +27,7 @@ import org.jetbrains.dokka.utilities.DokkaLogger
import org.jetbrains.dokka.versioning.ReplaceVersionsCommand
import org.jetbrains.dokka.versioning.VersioningConfiguration
import org.jetbrains.dokka.versioning.VersioningPlugin
import java.io.File

class MultimodulePageCreator(
private val context: DokkaContext,
Expand All @@ -49,6 +51,15 @@ class MultimodulePageCreator(
configuration<VersioningPlugin, VersioningConfiguration>(context)?.let {
group(extra = PropertyContainer.withAll(InsertTemplateExtra(ReplaceVersionsCommand))) { }
}
getMultiModuleDocumentation(context.configuration.includes).takeIf { it.isNotEmpty() }?.let { nodes ->
group(kind = ContentKind.Cover) {
nodes.forEach { node ->
group {
node.children.forEach { comment(it.root) }
}
}
}
}
header(2, "All modules:")
table(styles = setOf(MultimoduleTable)) {
header { group { text("Name") } }
Expand Down Expand Up @@ -83,6 +94,9 @@ class MultimodulePageCreator(
)
}

private fun getMultiModuleDocumentation(files: Set<File>): List<DocumentationNode> =
files.map { MarkdownParser({ null }, it.absolutePath).parse(it.readText()) }

private fun getDisplayedModuleDocumentation(module: DokkaModuleDescription): P? {
val parsingContext = ModuleAndPackageDocumentationParsingContext(logger)

Expand Down
@@ -0,0 +1,65 @@
package org.jetbrains.dokka.allModulesPage.templates

import matchers.content.*
import org.jetbrains.dokka.allModulesPage.MultiModuleAbstractTest
import org.jetbrains.dokka.model.dfs
import org.jetbrains.dokka.pages.ContentKind
import org.jetbrains.dokka.pages.ContentResolvedLink
import org.jetbrains.dokka.pages.MultimoduleRootPageNode
import org.junit.Rule
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.rules.TemporaryFolder
import kotlin.test.assertEquals

class MultiModuleDocumentationTest : MultiModuleAbstractTest() {
@get:Rule
val folder: TemporaryFolder = TemporaryFolder()

val documentationContent = """
# Sample project
Sample documentation with [external link](https://www.google.pl)
""".trimIndent()

@BeforeEach
fun setup() {
folder.create()
folder.root.resolve("README.md").writeText(documentationContent)
}

@Test
fun `documentation should be included in all modules page`() {
val configuration = dokkaConfiguration {
includes = listOf(folder.root.resolve("README.md"))
}

testFromData(configuration, preserveOutputLocation = true) {
allModulesPageCreationStage = { rootPage ->
(rootPage as? MultimoduleRootPageNode)?.content?.dfs { it.dci.kind == ContentKind.Cover }?.children?.firstOrNull()
?.assertNode {
group {
group {
group {
header(1) {
+"Sample project"
}
group {
+"Sample documentation with "
link {
+"external link"
check {
assertEquals(
"https://www.google.pl",
(this as ContentResolvedLink).address
)
}
}
}
}
}
}
}
}
}
}
}
7 changes: 7 additions & 0 deletions runners/cli/src/main/kotlin/cli/main.kt
Expand Up @@ -76,6 +76,13 @@ class GlobalArguments(args: Array<String>) : DokkaConfiguration {

override val suppressObviousFunctions: Boolean by lazy{ !noSuppressObviousFunctions }

private val _includes by parser.option(
ArgTypeFile,
description = "Markdown files that would be displayed in multi-module page separated by the semicolon `;`)"
).delimiter(";")

override val includes: Set<File> by lazy { _includes.toSet() }

val globalPackageOptions by parser.option(
ArgType.String,
description = "List of package source sets in format \"prefix,-deprecated,-privateApi,+warnUndocumented,+suppress;...\" "
Expand Down
Expand Up @@ -19,7 +19,6 @@ import org.jetbrains.dokka.plugability.ConfigurableBlock
import org.jetbrains.dokka.plugability.DokkaPlugin
import java.io.File
import java.util.function.BiConsumer
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance

abstract class AbstractDokkaTask : DefaultTask() {
Expand Down
@@ -1,11 +1,9 @@
package org.jetbrains.dokka.gradle

import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.internal.tasks.TaskDependencyInternal
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputDirectories
import org.gradle.api.tasks.*
import org.jetbrains.dokka.DokkaConfigurationImpl
import org.jetbrains.dokka.DokkaModuleDescriptionImpl
import java.io.File
Expand All @@ -17,6 +15,9 @@ typealias DokkaMultimoduleTask = DokkaMultiModuleTask
private typealias TaskPath = String

abstract class DokkaMultiModuleTask : AbstractDokkaParentTask() {
@InputFiles
@Optional
val includes: ConfigurableFileCollection = project.files()

@Internal
val fileLayout: Property<DokkaMultiModuleFileLayout> = project.objects.safeProperty<DokkaMultiModuleFileLayout>()
Expand All @@ -32,7 +33,7 @@ abstract class DokkaMultiModuleTask : AbstractDokkaParentTask() {

@get:Input
internal val childDokkaTaskIncludes: Map<TaskPath, Set<File>>
get() = childDokkaTasks.filterIsInstance<DokkaTask>().associate { task ->
get() = childDokkaTasks.filterIsInstance<DokkaTaskPartial>().associate { task ->
task.path to task.dokkaSourceSets.flatMap { it.includes }.toSet()
}

Expand Down Expand Up @@ -61,7 +62,8 @@ abstract class DokkaMultiModuleTask : AbstractDokkaParentTask() {
includes = childDokkaTaskIncludes[dokkaTask.path].orEmpty(),
sourceOutputDirectory = dokkaTask.outputDirectory.getSafe()
)
}
},
includes = includes.toSet(),
)
}

Expand Up @@ -22,7 +22,7 @@ class DokkaMultiModuleTaskTest {
.withProjectDir(rootProject.projectDir.resolve("child"))
.withParent(rootProject).build()

private val childDokkaTask = childProject.tasks.create<DokkaTask>("childDokkaTask")
private val childDokkaTask = childProject.tasks.create<DokkaTaskPartial>("childDokkaTask")

private val multiModuleTask = rootProject.tasks.create<DokkaMultiModuleTask>("multiModuleTask").apply {
addChildTask(childDokkaTask)
Expand Down Expand Up @@ -53,6 +53,7 @@ class DokkaMultiModuleTaskTest {
fun buildDokkaConfiguration() {
val include1 = childDokkaTask.project.file("include1.md")
val include2 = childDokkaTask.project.file("include2.md")
val topLevelInclude = multiModuleTask.project.file("README.md")

childDokkaTask.apply {
dokkaSourceSets.create("main")
Expand All @@ -69,6 +70,7 @@ class DokkaMultiModuleTaskTest {
pluginsConfiguration.add(PluginConfigurationImpl("pluginA", DokkaConfiguration.SerializationFormat.JSON, """ { "key" : "value2" } """))
failOnWarning by true
offlineMode by true
includes.from(listOf(topLevelInclude))
}

val dokkaConfiguration = multiModuleTask.buildDokkaConfiguration()
Expand All @@ -81,6 +83,7 @@ class DokkaMultiModuleTaskTest {
pluginsClasspath = emptyList(),
failOnWarning = true,
offlineMode = true,
includes = setOf(topLevelInclude),
modules = listOf(
DokkaModuleDescriptionImpl(
name = "child",
Expand All @@ -100,7 +103,7 @@ class DokkaMultiModuleTaskTest {
assertEquals(1, dependenciesInitial.size, "Expected one dependency")
val dependency = dependenciesInitial.single()

assertTrue(dependency is DokkaTask, "Expected dependency to be of Type ${DokkaTask::class.simpleName}")
assertTrue(dependency is DokkaTaskPartial, "Expected dependency to be of Type ${DokkaTaskPartial::class.simpleName}")
assertEquals(childProject, dependency.project, "Expected dependency from child project")


Expand Down Expand Up @@ -138,7 +141,7 @@ class DokkaMultiModuleTaskTest {
}

val secondChildDokkaTaskInclude = childProject.file("include4")
val secondChildDokkaTask = childProject.tasks.create<DokkaTask>("secondChildDokkaTask") {
val secondChildDokkaTask = childProject.tasks.create<DokkaTaskPartial>("secondChildDokkaTask") {
dokkaSourceSets.create("main") {
it.includes.from(secondChildDokkaTaskInclude)
}
Expand Down