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

how to generate documentation for a multi module gradle build #157

Closed
encodeering opened this issue May 16, 2017 · 15 comments
Closed

how to generate documentation for a multi module gradle build #157

encodeering opened this issue May 16, 2017 · 15 comments

Comments

@encodeering
Copy link

Hello,

just wanted to ask if you know a working configuration that either

  • aggregates all files from the subprojects or
  • generates a documentation including all subprojects at once

Tried something for the latter and came up with:

task dokka (type: org.jetbrains.dokka.gradle.DokkaTask, overwrite: true) {
    moduleName = "$rootProject.name"
    outputDirectory = "$buildDir/javadoc"
    outputFormat = "html"
    processConfigurations = []
    sourceDirs = files (subprojects.collect {
        p ->
            def path = "modules/${p.name}/src/main/kotlin"

            linkMapping {
                dir = path
                url = "https://....../blob/master/$path"
                suffix = "#L"
            }

            return "$rootProject.rootDir/$path"
    })
}

which works if the processConfigurations property is empty, but wont show any cross-reference in the generated html files then.

Any idea how to configure the classpath of related subprojects?

Thank you very much!

@semoro
Copy link
Contributor

semoro commented May 16, 2017

First approach requires a lot of work with linking, so the second one is preferred.
What do yo mean by but wont show any cross-reference in the generated html files then.,
just checked with Dokka itself and your config, works fine for me.
Modified it a bit

task dokka (type: org.jetbrains.dokka.gradle.DokkaTask, overwrite: true) {
    moduleName = "$rootProject.name"
    outputDirectory = "$buildDir/ddoc"
    outputFormat = "html"
    processConfigurations = []

    sourceDirs = files(subprojects.collect {
        p ->

            def path = new File(p.projectDir, "/src/main/kotlin")

            def relativePath = rootDir.toPath().relativize(path.toPath()).toString()
            linkMapping {
                dir = path
                url = "https://....../blob/master/$relativePath"
                suffix = "#L"
            }

            return path
    })
}

@encodeering
Copy link
Author

Oh sorry, was not precise enough about the cross-reference.

The link mappings are fine and refer to the correct repository sources, but the documentation shows a lot of <ERROR CLASS> entries, due the missing classpath dependencies, like kotlin-stdlib and so on.

Thought that I have to configure the processConfigurations property, but can't manage this for the string values, which refer to the configuration names?

Would it be possible to use a different string format to refer to a subproject and the corresponding configuration, which gets evaluated at runtime?

e.g. $subproject-name:compile

@alex2069
Copy link
Contributor

alex2069 commented May 18, 2017

Since each of my modules use Dokka for Javadoc generation, but I also wanted an interlinked Markdown version (for GitHub pages), I made a separate module that depended on all other modules (probably not necessary for just Dokka but I use it for other things as well):

dependencies {
    // Kotlin
    compile project.kotlinStdLib

    // Modules
    compile project(':module1')
    compile project(':module2')
    compile project(':moduleN')
    ...
}

apply plugin: 'org.jetbrains.dokka-android'
dokka {
    includes = ['Module.md']
    moduleName = 'dokka'
    outputFormat = 'gfm'
    outputDirectory = 'docs'
}

project.afterEvaluate {
    def mainDokkaTask = project.getTasksByName('dokka', false).first()
    rootProject.getTasksByName('dokka', true).forEach { libDokkaTask ->
        mainDokkaTask.sourceDirs = libDokkaTask.project.isAndroid ?
                libDokkaTask.project.android.sourceSets.main.java.srcDirs :
                libDokkaTask.project.sourceSets.main.allSource

        libDokkaTask.dependsOn 'assemble'

        mainDokkaTask.linkMapping {
            dir = "$rootDir/${libDokkaTask.project.name}/src/main/java"
            url = "https://github.com/user/project/tree/master/${libDokkaTask.project.name}/src/main/java"
            suffix = "#L"
        }

        if (libDokkaTask != mainDokkaTask) {
            mainDokkaTask.dependsOn libDokkaTask
        }
    }

    mainDokkaTask.dependsOn clearDokkaTask
    mainDokkaTask.dokkaFatJar project.dokkaFatJar
}

Having said all that, it would be nice if this was more officially supported so we could have proper bread crumbs that went from "Project > Module > Normal > Dokka > Path" etc.
Briefly looked into this but it did not look like a trivial task at all. x.x

@encodeering
Copy link
Author

Thank you for the example. I followed your suggestion and added the subprojects as module dependency to a custom configuration named dokkapath, which could be then used as value for processConfigurations = ['dokkapath'] to build the classpath.

configurations {
    dokkapath
    dokkapath.description = "dokka project classpath"
}

dependencies {
    subprojects.findAll { p -> dokkapath project (p.name) }
}

Had to set the repositories closure on the parent project for the dependency resolution, but all <ERROR CLASS> are gone now. There might be some caveat with jars provided by plugins (e.g. Android), but I've added the corresponding repositories manually to circumvent this issue.

Maybe you can add some options to the plugin to simplify this process.

Thanks everyone!

encodeering added a commit to encodeering/conflate that referenced this issue May 25, 2017
* adds a dependency configuration for all sub-modules to create a classpath for dokka

NOTE

* see Kotlin/dokka#157
encodeering added a commit to encodeering/conflate that referenced this issue May 27, 2017
* adds a dependency configuration for all sub-modules to create a classpath for dokka
* uses javadoc format for artifacts

NOTE

* see Kotlin/dokka#157
@sdeleuze
Copy link

To have cross module references, you can also specify:

dependsOn {
	subprojects.collect {
		it.tasks.getByName("jar")
	}
}
doFirst {
	classpath = subprojects.collect { project -> project.jar.outputs.files.getFiles() }.flatten()
	classpath += files(subprojects.collect { it.sourceSets.main.compileClasspath })
}

+1 for native support!

@fwpascual
Copy link

fwpascual commented Jun 14, 2018

I believe I have succeeded in creating a roll-up documentation with a mixture of what is described by @alex2069 and @semoro. That being, I have created a standalone module for the purposes of documentation that is purely for depending on all other subprojects and bringing in their source directories.

It was my original goal to do this without a unique documentation module, and I could get most of this working in the root project build.gradle. However, any Android types were showing up as <Error Class>. I know this has to do with the classpath, but I could not figure out how to use the 'dokka-android' plugin within the root project to accomplish this. This is what led me to move this all to a subproject with the 'com.android.library' plugin applied and it just worked.

Does anyone know what's needed to get this to work in the root project or is it best to do as a submodule if I need to reference Android?

Here's the block I was using in my root project build.gradle:

apply plugin: 'org.jetbrains.dokka-android'
dokka {
    moduleName = "$rootProject.name"
    outputDirectory = "$buildDir/docs"
    outputFormat = "html"
    jdkVersion = 8

    sourceDirs = files(subprojects.collect { p -> new File(p.projectDir, "/src/main/java") })
}

@motorro
Copy link

motorro commented Feb 28, 2019

Here is a complete 'gradle-native' solution that worked for me based on @sdeleuze answer (fixed a little to define sourceDirs).

In modules that require documentation to be generated (just to mark them relevantly):

apply plugin: 'org.jetbrains.dokka'

In top-most build.gradle:

/**
 * Finds sub-projects that need dokka generation
 * Place `apply plugin: 'org.jetbrains.dokka'` there
 * @return A set of projects that have dokka task
 */
Set<Project> findDokkaProjects() {
    subprojects.findAll {
        !it.tasks.findAll { "dokka" == it.getName() }.isEmpty()
    }
}

task dokka (type: org.jetbrains.dokka.gradle.DokkaTask, overwrite: true) {
    outputDirectory = docDir
    outputFormat = "gfm"

    dependsOn {
        findDokkaProjects().collect {
            it.tasks.getByName("dokka")
        }
    }

    doFirst {
        def dokkaProjects = findDokkaProjects()

        classpath = dokkaProjects.collect { project -> project.jar.outputs.files.getFiles() }.flatten()
        classpath += files(dokkaProjects.collect { project -> project.sourceSets.main.compileClasspath })

        sourceDirs = files(dokkaProjects.collect { project -> "${project.projectDir}/src/main/kotlin" })
    }
}

@kamildoleglo
Copy link
Contributor

Hi there, I've made a basic example of a multiproject generation. I think it might help you 🙂 Kotlin/kotlin-examples#103

@npike
Copy link

npike commented May 30, 2019

To build off of @fwpascual, this is what I am using in an Android SDK that contains multiple modules:

  1. documentation module, that basically just links the sourceSets for each of the actual modules I want documentation for, and the dokka config:
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
   compileSdkVersion 28

   defaultConfig {
       minSdkVersion 21
       targetSdkVersion 28
       versionCode 1
       versionName "1.0"

   }

   sourceSets {
       main.java.srcDirs += '../moduleA/src/main/java'
       main.java.srcDirs += '../moduleB/src/main/java'
   }
}


apply from: rootProject.file('dokka.gradle')
  1. dokka setup (dokka.gradle) (pretty standard setup)
apply plugin: 'org.jetbrains.dokka-android'

/**
 * See https://github.com/Kotlin/dokka
 */
dokka {
    moduleName = "$rootProject.name"
    outputFormat = 'html'
    outputDirectory = "$buildDir/javadoc"

    // Do not output deprecated members
    skipDeprecated = true

    // Emit warnings about not documented members.
    reportUndocumented = true

    // Do not create index pages for empty packages
    skipEmptyPackages = true
}
  1. then run ./gradlew documentation:dokka to generate merged documentation!

@Garf1eldGit
Copy link

First approach requires a lot of work with linking, so the second one is preferred.
What do yo mean by but wont show any cross-reference in the generated html files then.,
just checked with Dokka itself and your config, works fine for me.
Modified it a bit

task dokka (type: org.jetbrains.dokka.gradle.DokkaTask, overwrite: true) {
    moduleName = "$rootProject.name"
    outputDirectory = "$buildDir/ddoc"
    outputFormat = "html"
    processConfigurations = []

    sourceDirs = files(subprojects.collect {
        p ->

            def path = new File(p.projectDir, "/src/main/kotlin")

            def relativePath = rootDir.toPath().relativize(path.toPath()).toString()
            linkMapping {
                dir = path
                url = "https://....../blob/master/$relativePath"
                suffix = "#L"
            }

            return path
    })
}

Could not set unknown property 'moduleName' for task ':dokka' of type org.jetbrains.dokka.gradle.DokkaTask.

@yzg-github
Copy link

@Armaxis
a model in Android.
i set sourceDirs = files("XXX","XXX") in dokka {}, but the error : Could not set unknown property 'sourceDirs' for task ':model:dokka' of type org.jetbrains.dokka.gradle.DokkaTask.
i can't find any complete example for an android model to Generate api documentation in kotlin. This is incredible.

@Kordyjan
Copy link
Contributor

Kordyjan commented Sep 1, 2020

I'm closing this issue as it was a discussion for old dokka. New dokka (starting from 1.4.0-rc) is a complete rewrite and I encourage you to switch to it. It comes with multimodule tasks predefined:

  • dokkaHtmlCollector that gathers and merges documentation from all modules
  • dokkaHtmlMultimodule that documents modules as entities one level higher than packages
    They are not yet considered stable, but you can try them and give us some feedback. We are constantly tweaking them.

@rescribet
Copy link

rescribet commented Jan 4, 2022

Came across this since the multimodule example doesn't add id("org.jetbrains.dokka") version "1.6.10" in its build.gradle.kts, which I needed to add before the dokkaHtmlMultimodule task became available

@IgnatBeresnev
Copy link
Member

@rescribet JFYI it does so in settings.gradle.kts

pluginManagement {
    plugins {
        kotlin("jvm") version "1.6.10"
        id("org.jetbrains.dokka") version ("1.6.10")
    }
}

Perhaps this needs to be pointed out

@rescribet
Copy link

@IgnatBeresnev Ah, thanks. I'm don't have a JVM background, so I did not figure to check that file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests