diff options
12 files changed, 177 insertions, 15 deletions
diff --git a/core/src/main/kotlin/DokkaException.kt b/core/src/main/kotlin/DokkaException.kt new file mode 100644 index 00000000..0010249c --- /dev/null +++ b/core/src/main/kotlin/DokkaException.kt @@ -0,0 +1,3 @@ +package org.jetbrains.dokka + +class DokkaException(message: String) : RuntimeException(message) diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index c8a892d7..b2e572d4 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -54,9 +54,7 @@ class DokkaGenerator( report("Rendering") render(transformedPages, context) - context.unusedPoints.takeIf { it.isNotEmpty() } - ?.also { logger.warn("Unused extension points found: ${it.joinToString(", ")}") } - logger.report() + reportAfterRendering(context) }.dump("\n\n === TIME MEASUREMENT ===\n") fun generateAllModulesPage() = timed { @@ -138,6 +136,20 @@ class DokkaGenerator( renderer.render(transformedPages) } + fun reportAfterRendering(context: DokkaContext) { + context.unusedPoints.takeIf { it.isNotEmpty() }?.also { + logger.warn("Unused extension points found: ${it.joinToString(", ")}") + } + + logger.report() + + if (context.configuration.failOnWarning && (logger.warningsCount > 0 || logger.errorsCount > 0)) { + throw DokkaException( + "Failed with warningCount=${logger.warningsCount} and errorCount=${logger.errorsCount}" + ) + } + } + private fun createEnvironmentAndFacade( configuration: DokkaConfiguration, pass: DokkaConfiguration.PassConfiguration @@ -211,4 +223,10 @@ private class Timer(startTime: Long, private val logger: DokkaLogger?) { } private fun timed(logger: DokkaLogger? = null, block: Timer.() -> Unit): Timer = - Timer(System.currentTimeMillis(), logger).apply(block).apply { report("") }
\ No newline at end of file + Timer(System.currentTimeMillis(), logger).apply { + try { + block() + } finally { + report("") + } + } diff --git a/core/src/main/kotlin/configuration.kt b/core/src/main/kotlin/configuration.kt index fab7af37..f5115435 100644 --- a/core/src/main/kotlin/configuration.kt +++ b/core/src/main/kotlin/configuration.kt @@ -33,6 +33,7 @@ interface DokkaConfiguration { val modules: List<DokkaModuleDescription> val pluginsClasspath: List<File> val pluginsConfiguration: Map<String, String> + val failOnWarning: Boolean interface PassConfiguration { val moduleName: String diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt index 23cf7e2d..4e83d3c3 100644 --- a/core/src/main/kotlin/defaultConfiguration.kt +++ b/core/src/main/kotlin/defaultConfiguration.kt @@ -11,7 +11,8 @@ data class DokkaConfigurationImpl( override val passesConfigurations: List<PassConfigurationImpl>, override val pluginsClasspath: List<File>, override val pluginsConfiguration: Map<String, String>, - override val modules: List<DokkaModuleDescriptionImpl> + override val modules: List<DokkaModuleDescriptionImpl>, + override val failOnWarning: Boolean ) : DokkaConfiguration data class PassConfigurationImpl( diff --git a/plugins/base/src/test/kotlin/basic/FailOnWarningTest.kt b/plugins/base/src/test/kotlin/basic/FailOnWarningTest.kt new file mode 100644 index 00000000..2c805110 --- /dev/null +++ b/plugins/base/src/test/kotlin/basic/FailOnWarningTest.kt @@ -0,0 +1,118 @@ +package basic + +import org.jetbrains.dokka.DokkaException +import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.jetbrains.dokka.utilities.DokkaLogger +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import testApi.logger.TestLogger + +class FailOnWarningTest : AbstractCoreTest() { + + @Test + fun `throws exception if one or more warnings were emitted`() { + val configuration = dokkaConfiguration { + failOnWarning = true + passes { + pass { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + assertThrows<DokkaException> { + testInline( + """ + |/src/main/kotlin + |package sample + """.trimIndent(), configuration + ) { + analysisSetupStage = { + logger.warn("Warning!") + } + } + } + } + + @Test + fun `throws exception if one or more error were emitted`() { + val configuration = dokkaConfiguration { + failOnWarning = true + passes { + pass { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + assertThrows<DokkaException> { + testInline( + """ + |/src/main/kotlin + |package sample + """.trimIndent(), configuration + ) { + analysisSetupStage = { + logger.error("Error!") + } + } + } + } + + @Test + fun `does not throw if now warning or error was emitted`() { + logger = TestLogger(ZeroErrorOrWarningCountDokkaLogger()) + + val configuration = dokkaConfiguration { + failOnWarning = true + passes { + pass { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + + testInline( + """ + |/src/main/kotlin + |package sample + """.trimIndent(), configuration + ) { + /* We expect no Exception */ + } + } + + @Test + fun `does not throw if disabled`() { + val configuration = dokkaConfiguration { + failOnWarning = false + passes { + pass { + sourceRoots = listOf("src/main/kotlin") + } + } + } + + + testInline( + """ + |/src/main/kotlin + |package sample + """.trimIndent(), configuration + ) { + analysisSetupStage = { + logger.warn("Error!") + logger.error("Error!") + } + } + } +} + +private class ZeroErrorOrWarningCountDokkaLogger( + logger: DokkaLogger = DokkaConsoleLogger +) : DokkaLogger by logger { + override var warningsCount: Int = 0 + override var errorsCount: Int = 0 +}
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt index a4d7bd04..452439e9 100644 --- a/plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt @@ -36,7 +36,9 @@ abstract class RenderingOnlyTestBase { DokkaBase().externalLocationProviderFactory to { ::JavadocExternalLocationProviderFactory }, DokkaBase().externalLocationProviderFactory to { ::DokkaExternalLocationProviderFactory }, sourceSetCache = SourceSetCache(), - testConfiguration = DokkaConfigurationImpl("", "", null, false, emptyList(), emptyList(), emptyMap(), emptyList()) + testConfiguration = DokkaConfigurationImpl( + "", "", null, false, emptyList(), emptyList(), emptyMap(), emptyList(), false + ) ) protected val renderedContent: Element by lazy { @@ -50,7 +52,7 @@ abstract class RenderingOnlyTestBase { } -class TestPage(callback: PageContentBuilder.DocumentableContentBuilder.() -> Unit): RootPageNode(), ContentPage { +class TestPage(callback: PageContentBuilder.DocumentableContentBuilder.() -> Unit) : RootPageNode(), ContentPage { override val dri: Set<DRI> = setOf(DRI.topLevel) override val documentable: Documentable? = null override val embeddedResources: List<String> = emptyList() @@ -88,14 +90,14 @@ fun Element.match(vararg matchers: Any): Unit = .forEach { (n, m) -> m.accepts(n) } open class Tag(val name: String, vararg val matchers: Any) -class Div(vararg matchers: Any): Tag("div", *matchers) -class P(vararg matchers: Any): Tag("p", *matchers) -class Span(vararg matchers: Any): Tag("span", *matchers) +class Div(vararg matchers: Any) : Tag("div", *matchers) +class P(vararg matchers: Any) : Tag("p", *matchers) +class Span(vararg matchers: Any) : Tag("span", *matchers) private fun Any.accepts(n: Node) { when (this) { is String -> assert(n is TextNode && n.text().trim() == this.trim()) { "\"$this\" expected but found: $n" } - is Tag -> { + is Tag -> { assert(n is Element && n.tagName() == name) { "Tag $name expected but found: $n" } if (n is Element && matchers.isNotEmpty()) n.match(*matchers) } diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index d217f83e..2ef08c2e 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -46,6 +46,10 @@ open class GlobalArguments(parser: DokkaArgumentsParser) : DokkaConfiguration { "Offline mode (do not download package lists from the Internet)" ) + override val failOnWarning: Boolean by parser.singleFlag( + listOf("-failOnWarning"), "Fail dokka task if at least one warning was reported" + ) + override val passesConfigurations: List<Arguments> by parser.repeatableFlag( listOf("-pass"), "Single dokka pass" diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt index cad5e34f..2f821209 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt @@ -86,6 +86,9 @@ open class DokkaTask : DefaultTask(), Configurable { var disableAutoconfiguration: Boolean = false @Input + var failOnWarning: Boolean = false + + @Input var offlineMode: Boolean = false private var outputDiagnosticInfo: Boolean = @@ -199,6 +202,7 @@ open class DokkaTask : DefaultTask(), Configurable { passesConfigurations = defaultModulesConfiguration pluginsClasspath = pluginsClasspathConfiguration.resolve().toList() pluginsConfiguration = this@DokkaTask.pluginsConfiguration + failOnWarning = this@DokkaTask.failOnWarning } } diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt index 2787bb4e..3e08d27d 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/configurationImplementations.kt @@ -131,6 +131,7 @@ class GradleDokkaConfigurationImpl: DokkaConfiguration { override var pluginsClasspath: List<File> = emptyList() override var pluginsConfiguration: Map<String, String> = mutableMapOf() override var modules: List<GradleDokkaModuleDescription> = emptyList() + override var failOnWarning: Boolean = false } class GradlePackageOptionsImpl: PackageOptions, Serializable { diff --git a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt index 71fe5b40..5a739d5e 100644 --- a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt +++ b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt @@ -168,6 +168,9 @@ abstract class AbstractDokkaMojo : AbstractMojo() { var includeNonPublic: Boolean = false @Parameter + var failOnWarning: Boolean = false + + @Parameter var dokkaPlugins: List<Dependency> = emptyList() protected abstract fun getOutDir(): String @@ -250,7 +253,8 @@ abstract class AbstractDokkaMojo : AbstractMojo() { pluginsClasspath = getArtifactByAether("org.jetbrains.dokka", "dokka-base", dokkaVersion) + dokkaPlugins.map { getArtifactByAether(it.groupId, it.artifactId, it.version) }.flatten(), pluginsConfiguration = mutableMapOf(), //TODO implement as it is in Gradle - modules = emptyList() + modules = emptyList(), + failOnWarning = failOnWarning ) val gen = DokkaGenerator(configuration, logger) diff --git a/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt b/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt index 802bfd93..2ca8523b 100644 --- a/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt +++ b/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt @@ -25,7 +25,8 @@ internal class DokkaTestGenerator( ) analysisSetupStage(platforms) - val context = dokkaGenerator.initializePlugins(configuration, logger, platforms, sourceSetsCache, pluginOverrides) + val context = + dokkaGenerator.initializePlugins(configuration, logger, platforms, sourceSetsCache, pluginOverrides) pluginsSetupStage(context) val modulesFromPlatforms = dokkaGenerator.createDocumentationModels(platforms, context) @@ -48,5 +49,7 @@ internal class DokkaTestGenerator( dokkaGenerator.render(transformedPages, context) renderingStage(transformedPages, context) + + dokkaGenerator.reportAfterRendering(context) } }
\ No newline at end of file diff --git a/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt b/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt index edfc9049..3fde41a0 100644 --- a/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt +++ b/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt @@ -9,6 +9,7 @@ import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.jetbrains.dokka.utilities.DokkaLogger import org.junit.rules.TemporaryFolder import testApi.logger.TestLogger import java.io.File @@ -20,7 +21,7 @@ import java.nio.file.Paths // TODO: take dokka configuration from file abstract class AbstractCoreTest { - protected val logger = TestLogger(DokkaConsoleLogger) + protected var logger = TestLogger(DokkaConsoleLogger) protected fun getTestDataDir(name: String) = File("src/test/resources/$name").takeIf { it.exists() }?.toPath() @@ -143,6 +144,7 @@ abstract class AbstractCoreTest { var cacheRoot: String? = null var pluginsClasspath: List<File> = emptyList() var pluginsConfigurations: Map<String, String> = emptyMap() + var failOnWarning: Boolean = false private val passesConfigurations = mutableListOf<PassConfigurationImpl>() fun build() = DokkaConfigurationImpl( outputDir = outputDir, @@ -152,7 +154,8 @@ abstract class AbstractCoreTest { passesConfigurations = passesConfigurations, pluginsClasspath = pluginsClasspath, pluginsConfiguration = pluginsConfigurations, - modules = emptyList() + modules = emptyList(), + failOnWarning = failOnWarning ) fun passes(block: Passes.() -> Unit) { |