Kotlin / dokka

API documentation engine for Kotlin
https://kotl.in/dokka
Apache License 2.0
3.43k stars 407 forks source link

[Bug] Cannot Configure Custom Dokka Plugin #3869

Open solonovamax opened 1 day ago

solonovamax commented 1 day ago

Describe the Bug

It is currently impossible to configure custom dokka plugins.

Expected Behaviour

It should be possible to, and documented how to, configure custom dokka plugins.

Actual Behaviour

When attempting to configure custom dokka plugins with the (entirely undocumented) DokkaPluginParametersBuilder class and pluginParameters function, eg.

dokka {
    pluginsConfiguration {
        pluginParameters("ca.solostudios.dokkascript.plugin.DokkaScriptsPlugin") {
            files("scripts") {
                from(fileTree(dokkaScripts))
            }
        }
    }
}

then the following error is produced:

Cannot create a DokkaPluginParametersBuilder because this type is not known to this container. Known types are: DokkaHtmlPluginParameters, DokkaVersioningPluginParameters

If DokkaPluginParametersBuilder then has a factory registered using

dokka {
    pluginsConfiguration {
        registerFactory(DokkaPluginParametersBuilder::class.java) { name ->
            objects.newInstance<DokkaPluginParametersBuilder>(name, name)
        }
    }
}

then, gradle will properly load, however gradle will not allow the dokkaGenerate task to run, and instead produces the following error:

Some problems were found with the configuration of task ':dokkaGenerateModuleHtml' (type 'DokkaGenerateModuleTask').
  - Type 'org.jetbrains.dokka.gradle.engine.plugins.DokkaPluginParametersBuilder' method 'jsonEncode()' should not be annotated with: @Internal.

Environment

adam-enko commented 18 hours ago

Hi, thank you very much for the report and investigation.

For some context, the DokkaPluginParametersBuilder was an experiment from Dokkatoo that I started, but never finished, because I never found a need for it. It was intended as an improvement over the DGPv1 approach of manually writing JSON, and to correctly registering task inputs for Gradle task avoidance.

I've looked into DokkaPluginParametersBuilder further and aside from the issues you already found (bugs, missing docs, and missing functionality) I also found some more problems. I've discussed this with the Dokka team, and we're going to remove DokkaPluginParametersBuilder.

Alternative approach

For now you will have to avoid DokkaPluginParametersBuilder and instead implement a custom DokkaPluginParametersBaseSpec class. Such a class can be implemented in a build.gradle.kts. For example:

// build.gradle.kts

plugins {
  id("org.jetbrains.dokka") version "2.0.0-Beta"
}

val dokkaScripts = layout.projectDirectory.dir("dokka-scripts")

dokka {
  pluginsConfiguration {
    registerBinding(DokkaScriptsPluginParameters::class, DokkaScriptsPluginParameters::class)
    register<DokkaScriptsPluginParameters>("DokkaScripts") {
      scripts.from(dokkaScripts.asFileTree)
    }
  }
}

@OptIn(DokkaInternalApi::class)
abstract class DokkaScriptsPluginParameters @Inject constructor(
  name: String
) : DokkaPluginParametersBaseSpec(name, "ca.solostudios.dokkascript.plugin.DokkaScriptsPlugin") {

  @get:InputFiles
  @get:PathSensitive(PathSensitivity.RELATIVE)
  @get:NormalizeLineEndings
  abstract val scripts: ConfigurableFileCollection

  override fun jsonEncode(): String {
    val encodedScriptFiles = scripts.files.joinToString { "\"${it.canonicalFile.invariantSeparatorsPath}\"" }
    return """
      {
        "scripts": [ $encodedScriptFiles ]
      }
    """.trimIndent()
  }
}

If you find you need to re-use DokkaScriptsPluginParameters in multiple buildscripts, then I recommend moving the class into a shared location, like buildSrc (or another included-build for conventions).

Presently DokkaPluginParametersBaseSpec requires an opt-in for the internal Dokka Gradle API, but I'll look at removing this restriction.

Tasks

solonovamax commented 9 hours ago

For now you will have to avoid DokkaPluginParametersBuilder and instead implement a custom DokkaPluginParametersBaseSpec class. Such a class can be implemented in a build.gradle.kts. For example:

// build.gradle.kts

plugins {
  id("org.jetbrains.dokka") version "2.0.0-Beta"
}

val dokkaScripts = layout.projectDirectory.dir("dokka-scripts")

dokka {
  pluginsConfiguration {
    registerBinding(DokkaScriptsPluginParameters::class, DokkaScriptsPluginParameters::class)
    register<DokkaScriptsPluginParameters>("DokkaScripts") {
      scripts.from(dokkaScripts.asFileTree)
    }
  }
}

@OptIn(DokkaInternalApi::class)
abstract class DokkaScriptsPluginParameters @Inject constructor(
  name: String
) : DokkaPluginParametersBaseSpec(name, "ca.solostudios.dokkascript.plugin.DokkaScriptsPlugin") {

  @get:InputFiles
  @get:PathSensitive(PathSensitivity.RELATIVE)
  @get:NormalizeLineEndings
  abstract val scripts: ConfigurableFileCollection

  override fun jsonEncode(): String {
    val encodedScriptFiles = scripts.files.joinToString { "\"${it.canonicalFile.invariantSeparatorsPath}\"" }
    return """
      {
        "scripts": [ $encodedScriptFiles ]
      }
    """.trimIndent()
  }
}

If you find you need to re-use DokkaScriptsPluginParameters in multiple buildscripts, then I recommend moving the class into a shared location, like buildSrc (or another included-build for conventions).

I mentioned this in the slack, however this does not work and gradle will error with this. this is because it wants the class to be a static class, and for whatever reason if a class is declared in a buildscript, it is a non-static inner class

I also don't particularly want to introduce a buildSrc or a build-logic to my project, as that will increase builds needlessly, as my project does not utilize multiple subprojects.

solonovamax commented 2 hours ago

I mentioned this in the slack, however this does not work and gradle will error with this. this is because it wants the class to be a static class, and for whatever reason if a class is declared in a buildscript, it is a non-static inner class

I also don't particularly want to introduce a buildSrc or a build-logic to my project, as that will increase builds needlessly, as my project does not utilize multiple subprojects.

this is the specific issue, btw:

Could not create domain object 'scripts' (DokkaScriptsPluginParameters)
> Could not create an instance of type Build_gradle$DokkaScriptsPluginParameters.
   > Class Build_gradle.DokkaScriptsPluginParameters is a non-static inner class.

this is happening specifically because of the use of an ExtensiblePolymorphicDomainObjectContainer