From a2bc29f3fb15505e7350861f9f6d0281cb8d6191 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Wed, 4 Oct 2023 16:37:14 -0700 Subject: [PATCH 01/32] Bare minimum dokka configuration. --- build.gradle | 8 ++++++++ settings.gradle | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 18337728..bc21e2b0 100644 --- a/build.gradle +++ b/build.gradle @@ -5,3 +5,11 @@ repositories { mavenCentral() } apply from: rootProject.file('gradle/spotless.gradle') + +// ./gradlew dokkaHtmlMultiModule && open build/dokka/htmlMultiModule/index.html +subprojects { + if (it.name == 'selfie-lib' || it.name == 'selfie-runner-junit5') { + apply plugin: 'org.jetbrains.dokka' + } +} +apply plugin: 'org.jetbrains.dokka' diff --git a/settings.gradle b/settings.gradle index 498c23c9..f601691e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -18,7 +18,7 @@ plugins { // https://github.com/gradle-nexus/publish-plugin/releases id 'io.github.gradle-nexus.publish-plugin' version '1.3.0' apply false // https://plugins.gradle.org/plugin/org.jetbrains.dokka - id 'org.jetbrains.dokka' version '1.8.20' apply false + id 'org.jetbrains.dokka' version '1.9.0' apply false // https://plugins.gradle.org/plugin/org.jetbrains.kotlin.jvm id 'org.jetbrains.kotlin.jvm' version '1.9.10' apply false // https://plugins.gradle.org/plugin/org.jetbrains.kotlin.plugin.serialization @@ -36,6 +36,7 @@ blowdryerSetup { it.add "\t// https://plugins.gradle.org/plugin/org.jetbrains.kotlin.multiplatform" it.add "\tid 'org.jetbrains.kotlin.multiplatform' version '1.8.22' apply false" it.replace '1.8.22', '1.9.10' + it.replace '1.8.20', '1.9.0' it.replace '\t', ' ' } } From 40d6c0014c30b79ec3a1e9b2b862a37cc4cbcddd Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Wed, 4 Oct 2023 20:32:42 -0700 Subject: [PATCH 02/32] Dump the dokka plugin for dokkatoo (looks like IntelliJ is doing the same, lol) https://github.com/Kotlin/dokka/issues/3131 --- build.gradle | 40 ++++++++++++++++++++++++++++++++++++---- settings.gradle | 9 ++++++--- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index bc21e2b0..d55b1ba6 100644 --- a/build.gradle +++ b/build.gradle @@ -6,10 +6,42 @@ repositories { } apply from: rootProject.file('gradle/spotless.gradle') -// ./gradlew dokkaHtmlMultiModule && open build/dokka/htmlMultiModule/index.html +// ./gradlew :dokkatooGeneratePublicationHtml +// https://github.com/Kotlin/dokka/issues/3131 +// if IntelliJ is running, then you'll also get a localhost server link +def HAS_DOCS = [ + 'selfie-lib', + 'selfie-runner-junit5' +] +def FOOTER = "© 2023 DiffPlug LLC" + subprojects { - if (it.name == 'selfie-lib' || it.name == 'selfie-runner-junit5') { - apply plugin: 'org.jetbrains.dokka' + if (name in HAS_DOCS) { + apply plugin: 'dev.adamko.dokkatoo-html' + dokkatoo { + pluginsConfiguration.html { + footerMessage.set(FOOTER) + } + } + } +} +apply plugin: 'dev.adamko.dokkatoo-html' +dokkatoo { + pluginsConfiguration.html { + footerMessage.set(FOOTER) } } -apply plugin: 'org.jetbrains.dokka' +dependencies { + // aggregate both subproject-hello and subproject-world + // the subprojects must also have Dokkatoo applied + for (p in HAS_DOCS) { + dokkatoo(project(":${p}")) + } + + // This is required at the moment, see https://github.com/adamko-dev/dokkatoo/issues/14 + dokkatooPluginHtml( + dokkatoo.versions.jetbrainsDokka.map { dokkaVersion -> + "org.jetbrains.dokka:all-modules-page-plugin:$dokkaVersion" + } + ) +} diff --git a/settings.gradle b/settings.gradle index f601691e..7aa50b59 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,14 +17,14 @@ plugins { id 'dev.equo.ide' version '1.3.0' apply false // https://github.com/gradle-nexus/publish-plugin/releases id 'io.github.gradle-nexus.publish-plugin' version '1.3.0' apply false - // https://plugins.gradle.org/plugin/org.jetbrains.dokka - id 'org.jetbrains.dokka' version '1.9.0' apply false // https://plugins.gradle.org/plugin/org.jetbrains.kotlin.jvm id 'org.jetbrains.kotlin.jvm' version '1.9.10' apply false // https://plugins.gradle.org/plugin/org.jetbrains.kotlin.plugin.serialization id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.10' apply false // https://plugins.gradle.org/plugin/org.jetbrains.kotlin.multiplatform id 'org.jetbrains.kotlin.multiplatform' version '1.9.10' apply false + // https://github.com/adamko-dev/dokkatoo/releases + id 'dev.adamko.dokkatoo-html' version '2.0.0' apply false } blowdryerSetup { @@ -36,7 +36,10 @@ blowdryerSetup { it.add "\t// https://plugins.gradle.org/plugin/org.jetbrains.kotlin.multiplatform" it.add "\tid 'org.jetbrains.kotlin.multiplatform' version '1.8.22' apply false" it.replace '1.8.22', '1.9.10' - it.replace '1.8.20', '1.9.0' + it.add "\t// https://github.com/adamko-dev/dokkatoo/releases" + it.add "\tid 'dev.adamko.dokkatoo-html' version '2.0.0' apply false" + it.remove '\t// https://plugins.gradle.org/plugin/org.jetbrains.dokka' + it.remove "\tid 'org.jetbrains.dokka' version '1.8.20' apply false" it.replace '\t', ' ' } } From 42d60187f20e51690d988cdec28539866d12744e Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Wed, 4 Oct 2023 21:37:30 -0700 Subject: [PATCH 03/32] Add per-lib README's which are used by the Kotlin docs. --- build.gradle | 5 ++++- selfie-lib/README.md | 5 +++++ selfie-runner-junit5/README.md | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 selfie-lib/README.md create mode 100644 selfie-runner-junit5/README.md diff --git a/build.gradle b/build.gradle index d55b1ba6..ab67b045 100644 --- a/build.gradle +++ b/build.gradle @@ -13,12 +13,15 @@ def HAS_DOCS = [ 'selfie-lib', 'selfie-runner-junit5' ] -def FOOTER = "© 2023 DiffPlug LLC" +def FOOTER = "Selfie API Reference. © 2023 DiffPlug LLC" subprojects { if (name in HAS_DOCS) { apply plugin: 'dev.adamko.dokkatoo-html' dokkatoo { + dokkatooSourceSets.configureEach { + includes.from("README.md") + } pluginsConfiguration.html { footerMessage.set(FOOTER) } diff --git a/selfie-lib/README.md b/selfie-lib/README.md new file mode 100644 index 00000000..e82736c1 --- /dev/null +++ b/selfie-lib/README.md @@ -0,0 +1,5 @@ +# Module selfie-lib + +This Kotlin Multiplatform library makes it easy to read and write snapshot files. + +It is the guts that make the java and js runners work, but it's also reusable infrastructure if you want to build tooling on top of the snapshot files. \ No newline at end of file diff --git a/selfie-runner-junit5/README.md b/selfie-runner-junit5/README.md new file mode 100644 index 00000000..0151adc9 --- /dev/null +++ b/selfie-runner-junit5/README.md @@ -0,0 +1,3 @@ +# Module selfie-runner-junit5 + +High level docs for this live at TODO. From 463244c0a83f12aed35f4dda2bb047fc8582d1b5 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Wed, 4 Oct 2023 22:50:07 -0700 Subject: [PATCH 04/32] Put all the dokka customization into `dokkatoo.gradle`. --- build.gradle | 19 +------- gradle/dokka/README.md | 9 ++++ gradle/dokka/assets/logo-icon.svg | 56 ++++++++++++++++++++++ gradle/dokka/dokkatoo.gradle | 13 +++++ gradle/dokka/styles/logo-styles.css | 9 ++++ gradle/dokka/templates/includes/footer.ftl | 7 +++ gradle/dokka/templates/includes/header.ftl | 28 +++++++++++ 7 files changed, 124 insertions(+), 17 deletions(-) create mode 100644 gradle/dokka/README.md create mode 100644 gradle/dokka/assets/logo-icon.svg create mode 100644 gradle/dokka/dokkatoo.gradle create mode 100644 gradle/dokka/styles/logo-styles.css create mode 100644 gradle/dokka/templates/includes/footer.ftl create mode 100644 gradle/dokka/templates/includes/header.ftl diff --git a/build.gradle b/build.gradle index ab67b045..cb469738 100644 --- a/build.gradle +++ b/build.gradle @@ -13,27 +13,12 @@ def HAS_DOCS = [ 'selfie-lib', 'selfie-runner-junit5' ] -def FOOTER = "Selfie API Reference. © 2023 DiffPlug LLC" - subprojects { if (name in HAS_DOCS) { - apply plugin: 'dev.adamko.dokkatoo-html' - dokkatoo { - dokkatooSourceSets.configureEach { - includes.from("README.md") - } - pluginsConfiguration.html { - footerMessage.set(FOOTER) - } - } - } -} -apply plugin: 'dev.adamko.dokkatoo-html' -dokkatoo { - pluginsConfiguration.html { - footerMessage.set(FOOTER) + apply from: rootProject.file("gradle/dokka/dokkatoo.gradle") } } +apply from: rootProject.file("gradle/dokka/dokkatoo.gradle") dependencies { // aggregate both subproject-hello and subproject-world // the subprojects must also have Dokkatoo applied diff --git a/gradle/dokka/README.md b/gradle/dokka/README.md new file mode 100644 index 00000000..ba02e316 --- /dev/null +++ b/gradle/dokka/README.md @@ -0,0 +1,9 @@ +Main info is available at https://kotlinlang.org/docs/dokka-html.html + +But the gist is that [this folder](https://github.com/Kotlin/dokka/tree/master/plugins/base/src/main/resources/dokka) has + +- images (mainly `logo-icon.svg`) +- styles (`style.css`, `prism.css` (syntax highlighting), `logo-styles.css`) +- templates (`base.ftl`, `header.ftl`, `footer.ftl`) + +And we can override any of them in the root `build.gradle` inside the `dokkatoo` blocks. diff --git a/gradle/dokka/assets/logo-icon.svg b/gradle/dokka/assets/logo-icon.svg new file mode 100644 index 00000000..2e92d8c7 --- /dev/null +++ b/gradle/dokka/assets/logo-icon.svg @@ -0,0 +1,56 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/gradle/dokka/dokkatoo.gradle b/gradle/dokka/dokkatoo.gradle new file mode 100644 index 00000000..a21813ef --- /dev/null +++ b/gradle/dokka/dokkatoo.gradle @@ -0,0 +1,13 @@ +apply plugin: 'dev.adamko.dokkatoo-html' +dokkatoo { + if (project != rootProject) { + dokkatooSourceSets.configureEach { + includes.from("README.md") + } + } + pluginsConfiguration.html { + templatesDir.set(rootProject.file("gradle/dokka/templates")) + customStyleSheets.from(rootProject.file("gradle/dokka/styles/logo-styles.css")) + customAssets.from(rootProject.file("gradle/dokka/assets/logo-icon.svg")) + } +} diff --git a/gradle/dokka/styles/logo-styles.css b/gradle/dokka/styles/logo-styles.css new file mode 100644 index 00000000..fdfd137c --- /dev/null +++ b/gradle/dokka/styles/logo-styles.css @@ -0,0 +1,9 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + + :root { + --dokka-logo-image-url: url('../images/logo-icon.svg'); + --dokka-logo-height: 70px; + --dokka-logo-width: 70px; +} \ No newline at end of file diff --git a/gradle/dokka/templates/includes/footer.ftl b/gradle/dokka/templates/includes/footer.ftl new file mode 100644 index 00000000..461a8162 --- /dev/null +++ b/gradle/dokka/templates/includes/footer.ftl @@ -0,0 +1,7 @@ +<#macro display> + + \ No newline at end of file diff --git a/gradle/dokka/templates/includes/header.ftl b/gradle/dokka/templates/includes/header.ftl new file mode 100644 index 00000000..e9ec4f70 --- /dev/null +++ b/gradle/dokka/templates/includes/header.ftl @@ -0,0 +1,28 @@ +<#import "source_set_selector.ftl" as source_set_selector> +<#macro display> + + \ No newline at end of file From 28f2dd38ef5b2e6db6ad81d9b5a60cded84b8782 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Thu, 5 Oct 2023 01:20:55 -0700 Subject: [PATCH 05/32] .gitignore `.DS_Store`. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9dee44f6..b8c42e51 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .gradle/ build/ bin/ +.DS_Store \ No newline at end of file From a53aa5ffc06d6331964451168125edb11330a617 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Thu, 5 Oct 2023 01:21:16 -0700 Subject: [PATCH 06/32] Add some possibly useful art assets for the dokka design. --- gradle/dokka/assets/antique_bot.webp | Bin 0 -> 206168 bytes gradle/dokka/assets/antique_humanoid.webp | Bin 0 -> 162506 bytes gradle/dokka/assets/background_floral.webp | Bin 0 -> 19316 bytes gradle/dokka/assets/background_seaside.webp | Bin 0 -> 17368 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 gradle/dokka/assets/antique_bot.webp create mode 100644 gradle/dokka/assets/antique_humanoid.webp create mode 100644 gradle/dokka/assets/background_floral.webp create mode 100644 gradle/dokka/assets/background_seaside.webp diff --git a/gradle/dokka/assets/antique_bot.webp b/gradle/dokka/assets/antique_bot.webp new file mode 100644 index 0000000000000000000000000000000000000000..3acc3c4c57603ef9c53a2ffe808232ab8ba3037e GIT binary patch literal 206168 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