dokka icon indicating copy to clipboard operation
dokka copied to clipboard

[Bug] Cannot Configure Custom Dokka Plugin

Open solonovamax opened this issue 1 year ago • 4 comments

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

  • Operating system: Linux
  • Build tool: Gradle 8.10.1
  • Dokka version: 2.0.0-Beta

solonovamax avatar Oct 17 '24 02:10 solonovamax

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

  • [ ] Remove DokkaPluginParametersBuilder. It is an experimental feature that wasn't finished, and doesn't work as intended. https://github.com/Kotlin/dokka/pull/3872
  • [ ] Document custom plugin configuration (see example above).
  • [ ] Add example for custom plugin configuration. https://github.com/Kotlin/dokka/pull/3871
  • [ ] Investigate removing opt-in for DokkaPluginParametersBaseSpec.

adam-enko avatar Oct 17 '24 09:10 adam-enko

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 avatar Oct 17 '24 18:10 solonovamax

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

solonovamax avatar Oct 18 '24 01:10 solonovamax

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

Thanks for sharing the specific error. It looks like that's a Gradle error https://github.com/gradle/gradle/issues/25494, caused by referencing something from the buildscript inside of the class.

I'm working on a demonstration project here to show how to configure a custom DokkaScriptsPluginParameters.

If something still isn't working, please share an example (or link to an open source project) and I can take a look.

adam-enko avatar Oct 21 '24 09:10 adam-enko