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

Add global settings to JSON dokka cli input #2292

Merged
merged 3 commits into from Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions integration-tests/cli/build.gradle.kts
Expand Up @@ -12,6 +12,8 @@ evaluationDependsOn(":plugins:base")
dependencies {
implementation(kotlin("stdlib"))
implementation(kotlin("test-junit"))
val jackson_version: String by project
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version")
BarkingBad marked this conversation as resolved.
Show resolved Hide resolved
}

/* Create a fat base plugin jar for cli tests */
Expand All @@ -23,6 +25,7 @@ val basePluginShadow: Configuration by configurations.creating {

dependencies {
basePluginShadow(project(":plugins:base"))

}
val basePluginShadowJar by tasks.register("basePluginShadowJar", ShadowJar::class) {
configurations = listOf(basePluginShadow)
Expand Down
Expand Up @@ -2,6 +2,8 @@ package org.jetbrains.dokka.it.cli

import org.jetbrains.dokka.it.awaitProcessResult
import java.io.File
import java.io.PrintWriter
import java.lang.IllegalStateException
import kotlin.test.*

class CliIntegrationTest : AbstractCliIntegrationTest() {
Expand Down Expand Up @@ -193,7 +195,7 @@ class CliIntegrationTest : AbstractCliIntegrationTest() {
}

@Test
fun `logging level should be respected`(){
fun `logging level should be respected`() {
val dokkaOutputDir = File(projectDir, "output")
assertTrue(dokkaOutputDir.mkdirs())
val process = ProcessBuilder(
Expand Down Expand Up @@ -259,4 +261,111 @@ class CliIntegrationTest : AbstractCliIntegrationTest() {
)
)
}


@Test
fun json() {
BarkingBad marked this conversation as resolved.
Show resolved Hide resolved
val dokkaOutputDir = File(projectDir, "output")
assertTrue(dokkaOutputDir.mkdirs())
val jsonPath = javaClass.getResource("/my-file.json")?.path ?: throw IllegalStateException("No JSON found!")
PrintWriter(jsonPath).run {
write(jsonBuilder(dokkaOutputDir.path, basePluginJarFile.path, File(projectDir, "src").path, reportUndocumented = true))
close()
}

val process = ProcessBuilder(
"java", "-jar", cliJarFile.path, jsonPath
).redirectErrorStream(true).start()

val result = process.awaitProcessResult()
assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")

val extensionLoadedRegex = Regex("""Extension: org\.jetbrains\.dokka\.base\.DokkaBase""")
val amountOfExtensionsLoaded = extensionLoadedRegex.findAll(result.output).count()

assertTrue(
amountOfExtensionsLoaded > 10,
"Expected more than 10 extensions being present (found $amountOfExtensionsLoaded)"
)

val undocumentedReportRegex = Regex("""Undocumented:""")
val amountOfUndocumentedReports = undocumentedReportRegex.findAll(result.output).count()
assertTrue(
amountOfUndocumentedReports > 0,
"Expected at least one report of undocumented code (found $amountOfUndocumentedReports)"
)

assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
}

/**
* This test disables global `reportUndocumneted` property and set `reportUndocumented` via perPackageOptions to
* make sure that global settings apply to dokka context.
*/
@Test
fun jsonWithGlobals() {
BarkingBad marked this conversation as resolved.
Show resolved Hide resolved
val dokkaOutputDir = File(projectDir, "output")
assertTrue(dokkaOutputDir.mkdirs())
val jsonPath = javaClass.getResource("/my-file.json")?.path ?: throw IllegalStateException("No JSON found!")
PrintWriter(jsonPath).run {
write(
jsonBuilder(
outputPath = dokkaOutputDir.path,
pluginsClasspath = basePluginJarFile.path,
projectPath = File(projectDir, "src").path,
globalSourceLinks = """
{
"localDirectory": "/home/Vadim.Mishenev/dokka/examples/cli/src/main/kotlin",
"remoteUrl": "https://github.com/Kotlin/dokka/tree/master/examples/gradle/dokka-gradle-example/src/main/kotlin",
"remoteLineSuffix": "#L"
}
""".trimIndent(),
globalExternalDocumentationLinks = """
{
"url": "https://docs.oracle.com/javase/8/docs/api/",
"packageListUrl": "https://docs.oracle.com/javase/8/docs/api/package-list"
},
{
"url": "https://kotlinlang.org/api/latest/jvm/stdlib/",
"packageListUrl": "https://kotlinlang.org/api/latest/jvm/stdlib/package-list"
}
""".trimIndent(),
globalPerPackageOptions = """
{
"matchingRegex": ".*",
"skipDeprecated": "true",
"reportUndocumented": "true",
"documentedVisibilities": ["PUBLIC", "PRIVATE", "PROTECTED", "INTERNAL", "PACKAGE"]
}
""".trimIndent(),
reportUndocumented = false
),
)
close()
}

val process = ProcessBuilder(
"java", "-jar", cliJarFile.path, jsonPath
).redirectErrorStream(true).start()

val result = process.awaitProcessResult()
assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")

val extensionLoadedRegex = Regex("""Extension: org\.jetbrains\.dokka\.base\.DokkaBase""")
val amountOfExtensionsLoaded = extensionLoadedRegex.findAll(result.output).count()

assertTrue(
amountOfExtensionsLoaded > 10,
"Expected more than 10 extensions being present (found $amountOfExtensionsLoaded)"
)

val undocumentedReportRegex = Regex("""Undocumented:""")
val amountOfUndocumentedReports = undocumentedReportRegex.findAll(result.output).count()
assertTrue(
amountOfUndocumentedReports > 0,
"Expected at least one report of undocumented code (found $amountOfUndocumentedReports)"
)

assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")
}
}
@@ -0,0 +1,52 @@
package org.jetbrains.dokka.it.cli

fun jsonBuilder(
outputPath: String,
pluginsClasspath: String,
projectPath: String,
globalSourceLinks: String = "",
globalExternalDocumentationLinks: String = "",
globalPerPackageOptions: String = "",
reportUndocumented: Boolean = false

): String {
return """{
"moduleName": "Dokka Example",
"moduleVersion": null,
"outputDir": "$outputPath",
"pluginsClasspath": ["$pluginsClasspath"],
"cacheRoot": null,
"offlineMode": false,
"sourceLinks": [$globalSourceLinks],
"externalDocumentationLinks": [$globalExternalDocumentationLinks],
"perPackageOptions": [$globalPerPackageOptions],
"sourceSets": [
{
"displayName": "jvm",
"sourceSetID": {
"scopeId": ":dokkaHtml",
"sourceSetName": "main"
},
"sourceRoots": [
"$projectPath"
],
"dependentSourceSets": [],
"samples": [],
"includes": [],
"includeNonPublic": false,
"reportUndocumented": $reportUndocumented,
"skipEmptyPackages": true,
"skipDeprecated": false,
"jdkVersion": 8,
"sourceLinks": [],
"perPackageOptions": [],
"externalDocumentationLinks": [],
"noStdlibLink": false,
"noJdkLink": false,
"suppressedFiles": [],
"analysisPlatform": "jvm"
}
]
}
"""
}
Empty file.
10 changes: 10 additions & 0 deletions plugins/all-modules-page/out/index.md
@@ -0,0 +1,10 @@
/

# Sample project

Sample documentation with [external link](https://www.google.pl)

## All modules:

| Name |
|---|
BarkingBad marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion plugins/base/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions runners/cli/api/cli.api
Expand Up @@ -87,9 +87,37 @@ public final class org/jetbrains/dokka/GlobalArguments : org/jetbrains/dokka/Dok
public fun getSuppressObviousFunctions ()Z
}

public final class org/jetbrains/dokka/GlobalDokkaConfiguration {
public fun <init> (Ljava/util/List;Ljava/util/List;Ljava/util/List;)V
public final fun component1 ()Ljava/util/List;
public final fun component2 ()Ljava/util/List;
public final fun component3 ()Ljava/util/List;
public final fun copy (Ljava/util/List;Ljava/util/List;Ljava/util/List;)Lorg/jetbrains/dokka/GlobalDokkaConfiguration;
public static synthetic fun copy$default (Lorg/jetbrains/dokka/GlobalDokkaConfiguration;Ljava/util/List;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/GlobalDokkaConfiguration;
public fun equals (Ljava/lang/Object;)Z
public final fun getExternalDocumentationLinks ()Ljava/util/List;
public final fun getPerPackageOptions ()Ljava/util/List;
public final fun getSourceLinks ()Ljava/util/List;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class org/jetbrains/dokka/JsonMapperForCLIKt {
public static final fun parseJson (Ljava/lang/String;Lorg/jetbrains/dokka/TypeReference;)Ljava/lang/Object;
}

public final class org/jetbrains/dokka/MainKt {
public static final fun defaultLinks (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Ljava/util/List;
public static final fun initializeConfiguration (Lorg/jetbrains/dokka/GlobalArguments;)Lorg/jetbrains/dokka/DokkaConfiguration;
public static final fun main ([Ljava/lang/String;)V
public static final fun parseLinks (Ljava/util/List;)Ljava/util/List;
}

public final class org/jetbrains/dokka/TypeReference {
public static final field Companion Lorg/jetbrains/dokka/TypeReference$Companion;
public synthetic fun <init> (Lcom/fasterxml/jackson/core/type/TypeReference;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class org/jetbrains/dokka/TypeReference$Companion {
}

4 changes: 4 additions & 0 deletions runners/cli/build.gradle.kts
Expand Up @@ -10,6 +10,10 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-cli-jvm:0.3.3")
implementation(project(":core"))
implementation(kotlin("stdlib"))
val jackson_version: String by project
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version")
BarkingBad marked this conversation as resolved.
Show resolved Hide resolved

testImplementation(kotlin("test-junit"))
}

tasks {
Expand Down
48 changes: 48 additions & 0 deletions runners/cli/src/main/kotlin/cli/JsonMapperForCLI.kt
@@ -0,0 +1,48 @@
package org.jetbrains.dokka

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
import java.io.File

// THIS IS COPIED FROM BASE SINCE IT NEEDS TO BE INSTANTIATED ON THE SAME CLASS LOADER AS PLUGINS

BarkingBad marked this conversation as resolved.
Show resolved Hide resolved
private val objectMapper = run {
val module = SimpleModule().apply {
addSerializer(FileSerializer)
}
jacksonObjectMapper()
.registerModule(module)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
}

@PublishedApi
internal class TypeReference<T> private constructor(
internal val jackson: com.fasterxml.jackson.core.type.TypeReference<T>
) {
companion object {
internal inline operator fun <reified T> invoke(): TypeReference<T> = TypeReference(jacksonTypeRef())
}
}

inline fun <reified T : Any> parseJson(json: String): T = parseJson(json, TypeReference())

@PublishedApi
internal fun <T : Any> parseJson(json: String, typeReference: TypeReference<T>): T =
objectMapper.readValue(json, typeReference.jackson)

private object FileSerializer : StdScalarSerializer<File>(File::class.java) {
override fun serialize(value: File, g: JsonGenerator, provider: SerializerProvider) {
g.writeString(value.path)
}
}

data class GlobalDokkaConfiguration(
val perPackageOptions: List<PackageOptionsImpl>?,
val externalDocumentationLinks: List<ExternalDocumentationLinkImpl>?,
val sourceLinks: List<SourceLinkDefinitionImpl>?
)
BarkingBad marked this conversation as resolved.
Show resolved Hide resolved
39 changes: 29 additions & 10 deletions runners/cli/src/main/kotlin/cli/main.kt
Expand Up @@ -2,10 +2,7 @@ package org.jetbrains.dokka

import kotlinx.cli.*
import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink
import org.jetbrains.dokka.utilities.DokkaConsoleLogger
import org.jetbrains.dokka.utilities.DokkaLogger
import org.jetbrains.dokka.utilities.LoggingLevel
import org.jetbrains.dokka.utilities.cast
import org.jetbrains.dokka.utilities.*
import java.io.*
import java.net.MalformedURLException
import java.net.URL
Expand Down Expand Up @@ -80,6 +77,7 @@ class GlobalArguments(args: Array<String>) : DokkaConfiguration {

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

Expand Down Expand Up @@ -406,14 +404,35 @@ fun parseLinks(links: List<String>): List<ExternalDocumentationLink> {
}
}

fun initializeConfiguration(globalArguments: GlobalArguments): DokkaConfiguration = if (globalArguments.json != null) {
val jsonContent = Paths.get(checkNotNull(globalArguments.json)).toFile().readText()
val globals: GlobalDokkaConfiguration = parseJson(jsonContent)
val dokkaConfigurationImpl = DokkaConfigurationImpl(jsonContent)
dokkaConfigurationImpl.run {
BarkingBad marked this conversation as resolved.
Show resolved Hide resolved
sourceSets.forEach {
it.perPackageOptions.cast<MutableList<DokkaConfiguration.PackageOptions>>().addAll(globals.perPackageOptions ?: emptyList())
}

sourceSets.forEach {
it.externalDocumentationLinks.cast<MutableSet<ExternalDocumentationLink>>().addAll(globals.externalDocumentationLinks ?: emptyList())
}

sourceSets.forEach {
it.sourceLinks.cast<MutableSet<SourceLinkDefinitionImpl>>().addAll(globals.sourceLinks ?: emptyList())
}

sourceSets.forEach {
it.externalDocumentationLinks.cast<MutableSet<ExternalDocumentationLink>>().addAll(defaultLinks(it))
}
}
IgnatBeresnev marked this conversation as resolved.
Show resolved Hide resolved
dokkaConfigurationImpl
} else {
globalArguments
}

fun main(args: Array<String>) {
val globalArguments = GlobalArguments(args)
val configuration = if (globalArguments.json != null)
DokkaConfigurationImpl(
Paths.get(checkNotNull(globalArguments.json)).toFile().readText()
)
else
globalArguments
val configuration = initializeConfiguration(globalArguments)
DokkaGenerator(configuration, globalArguments.logger).generate()
}