From a752b6e30e516d4a132eb4f0dce4a8f9f8fb87a2 Mon Sep 17 00:00:00 2001 From: Mike Solomon Date: Mon, 7 Oct 2024 19:55:14 -0700 Subject: [PATCH] Support docusaurus (#136) * Replace {% stuff with Docusaurus stuff * Saving fixes * More docusaurus fixes * Fix link * Fix core recipe generation * Fix vars + options * Fix assertj issues * Remove auto-generated github pages Don't see a point for this anymore - and it would be a decent amount of work to get it working again. We can easily start up a docusaurus server locally with the changes if we want to see them. * Make recipes with data tables look better * Handle more bad recipe names * Handle C# better * Fix labeling I was using title= instead of label= which made capitalization wrong. I also didn't follow the pattern of fooBar and instead was doing foo-bar. Both have been fixed * More style fixes * Fix recipes with data tables * Handle HTML better + fix datatables further * Really fix datatables hopefully * Handle AI data tables --------- Co-authored-by: Mike Solomon --- .github/workflows/pages.yml | 58 -- .../openrewrite/RecipeDescriptorExtensions.kt | 10 +- .../openrewrite/RecipeMarkdownGenerator.kt | 529 ++++++++++-------- 3 files changed, 303 insertions(+), 294 deletions(-) delete mode 100644 .github/workflows/pages.yml diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml deleted file mode 100644 index 4d27f8f..0000000 --- a/.github/workflows/pages.yml +++ /dev/null @@ -1,58 +0,0 @@ -# Simple workflow for deploying static content to GitHub Pages -name: Deploy static content to Pages - -on: - push: - branches: - - main - tags-ignore: - - "*" - pull_request: - branches: - - main - workflow_dispatch: {} - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Single deploy job since we're just deploying - deploy: - if: ${{ github.repository_owner == 'openrewrite' }} - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 17 - - uses: gradle/actions/setup-gradle@v4 - - name: build - run: ./gradlew ${{ env.GRADLE_SWITCHES }} run - - - name: Create index.html - run: cp build/docs/SUMMARY_snippet.md build/docs/index.md - - - name: Setup Pages - uses: actions/configure-pages@v5 - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - # Upload entire repository - path: 'build/docs' - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 diff --git a/src/main/kotlin/org/openrewrite/RecipeDescriptorExtensions.kt b/src/main/kotlin/org/openrewrite/RecipeDescriptorExtensions.kt index d284d29..0813140 100755 --- a/src/main/kotlin/org/openrewrite/RecipeDescriptorExtensions.kt +++ b/src/main/kotlin/org/openrewrite/RecipeDescriptorExtensions.kt @@ -6,11 +6,11 @@ import org.openrewrite.config.RecipeDescriptor fun RecipeDescriptor.asYaml(): String { val s = StringBuilder() s.appendLine(""" - --- - type: specs.openrewrite.org/v1beta/recipe - name: $name - displayName: $displayName - description: $description +--- +type: specs.openrewrite.org/v1beta/recipe +name: $name +displayName: $displayName +description: ${description?.replace("\n", " – ") ?: ""} """.trimIndent()) if (tags.isNotEmpty()) { s.appendLine("tags:") diff --git a/src/main/kotlin/org/openrewrite/RecipeMarkdownGenerator.kt b/src/main/kotlin/org/openrewrite/RecipeMarkdownGenerator.kt index 9034fff..45476d9 100644 --- a/src/main/kotlin/org/openrewrite/RecipeMarkdownGenerator.kt +++ b/src/main/kotlin/org/openrewrite/RecipeMarkdownGenerator.kt @@ -104,7 +104,7 @@ class RecipeMarkdownGenerator : Runnable { override fun run() { val outputPath = Paths.get(destinationDirectoryName) - val recipesPath = outputPath.resolve("reference/recipes") + val recipesPath = outputPath.resolve("recipes") try { Files.createDirectories(recipesPath) } catch (e: IOException) { @@ -119,34 +119,7 @@ class RecipeMarkdownGenerator : Runnable { recipeOrigins = RecipeOrigin.parse(recipeSources) // Write latest-versions-of-every-openrewrite-module.md - val versionsSnippetPath = outputPath.resolve("latest-versions-of-every-openrewrite-module.md") - Files.newBufferedWriter(versionsSnippetPath, StandardOpenOption.CREATE).useAndApply { - val bomLink = "[${rewriteRecipeBomVersion}](https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v${rewriteRecipeBomVersion})" - val mavenLink = "[${mavenPluginVersion}](https://github.com/openrewrite/rewrite-maven-plugin/releases/tag/v${mavenPluginVersion})" - val gradleLink = "[${gradlePluginVersion}](https://github.com/openrewrite/rewrite-gradle-plugin/releases/tag/v${gradlePluginVersion})" - writeln(""" - # Latest versions of every OpenRewrite module - - OpenRewrite's modules are published to [Maven Central](https://search.maven.org/search?q=org.openrewrite). - Each time a release is made, a bill of materials artifact is also published to correctly align and manage the versions of all published artifacts. - The Gradle plugin is published to the [Gradle Plugin Portal](https://plugins.gradle.org/plugin/org.openrewrite.rewrite). - - It is highly recommended that developers use the [rewrite-recipe-bom](https://github.com/openrewrite/rewrite-recipe-bom) - to align the versions of Rewrite's modules to ensure compatibility. - The use of the "bill of materials" means that a developer will only need to specify explicit versions of the BOM and the build plugins: - - | Module | Version | - |-----------------------------------------------------------------------------------------------------------------------| ---------- | - | [**org.openrewrite.recipe:rewrite-recipe-bom**](https://github.com/openrewrite/rewrite-recipe-bom) | **${bomLink}** | - | [**org.openrewrite:rewrite-maven-plugin**](https://github.com/openrewrite/rewrite-maven-plugin) | **${mavenLink}** | - | [**org.openrewrite:rewrite-gradle-plugin**](https://github.com/openrewrite/rewrite-gradle-plugin) | **${gradleLink}** | - """.trimIndent()) - for (recipeOrigin in recipeOrigins.values) { - val repoLink = "[${recipeOrigin.groupId}:${recipeOrigin.artifactId}](${recipeOrigin.githubUrl()})" - val releaseLink = "[${recipeOrigin.version}](${recipeOrigin.githubUrl()}/releases/tag/v${recipeOrigin.version})" - writeln("| ${repoLink.padEnd(117)} | ${releaseLink} |") - } - } + createLatestVersionsFile(outputPath, recipeOrigins) val classloader = recipeClasspath.split(";") .map(Paths::get) @@ -321,18 +294,6 @@ class RecipeMarkdownGenerator : Runnable { val categories = Category.fromDescriptors(recipeDescriptors, categoryDescriptors).sortedBy { it.simpleName } - // Write SUMMARY_snippet.md - val summarySnippetPath = outputPath.resolve("SUMMARY_snippet.md") - Files.newBufferedWriter(summarySnippetPath, StandardOpenOption.CREATE).useAndApply { - for (category in categories) { - write(category.summarySnippet(0)) - } - write(""" - * [Changelog](changelog/changelog.md) - * [$rewriteBomVersion Release (${getDateFormattedYYYYMMDD()})](/changelog/${rewriteBomVersion.replace('.','-')}-Release.md) - """.trimIndent()) - } - // Write recipes-with-data-tables.md val recipesWithDataTablesPath = outputPath.resolve("recipes-with-data-tables.md") Files.newBufferedWriter(recipesWithDataTablesPath, StandardOpenOption.CREATE).useAndApply { @@ -343,9 +304,21 @@ class RecipeMarkdownGenerator : Runnable { "it won't be included in this list._\n") for (recipe in recipesWithDataTables) { - writeln("**[${recipe.displayName}](https://docs.openrewrite.org/?q=${recipe.name})** ") - writeln("**${recipe.name}** ") + var recipePath = ""; + + if (recipe.name.count { it == '.' } == 2 && + recipe.name.contains("org.openrewrite.")) { + recipePath = "recipes/core/" + recipe.name.removePrefix("org.openrewrite.").lowercase(); + } else if (recipe.name.contains("io.moderne.ai")) { + recipePath = "recipes/ai/" + recipe.name.removePrefix("io.moderne.ai.").replace(".", "/").lowercase(); + } else { + recipePath = "recipes/" + recipe.name.removePrefix("org.openrewrite.").replace(".", "/").lowercase(); + } + + writeln("### [${recipe.displayName}](../${recipePath})\n ") + writeln("_${recipe.name}_\n") writeln("${recipe.description}\n") + writeln("#### Data tables:\n") val filteredDataTables = recipe.dataTables.filter { dataTable -> dataTable.name !in dataTablesToIgnore @@ -361,11 +334,51 @@ class RecipeMarkdownGenerator : Runnable { // Write the README.md for each category for (category in categories) { - val categoryIndexPath = outputPath.resolve("reference/recipes/") + val categoryIndexPath = outputPath.resolve("recipes/") category.writeCategoryIndex(categoryIndexPath) } } + private fun createLatestVersionsFile( + outputPath: Path, + recipeOrigins: Map + ) { + val versionsSnippetPath = outputPath.resolve("latest-versions-of-every-openrewrite-module.md") + Files.newBufferedWriter(versionsSnippetPath, StandardOpenOption.CREATE).useAndApply { + val bomLink = + "[${rewriteRecipeBomVersion}](https://github.com/openrewrite/rewrite-recipe-bom/releases/tag/v${rewriteRecipeBomVersion})" + val mavenLink = + "[${mavenPluginVersion}](https://github.com/openrewrite/rewrite-maven-plugin/releases/tag/v${mavenPluginVersion})" + val gradleLink = + "[${gradlePluginVersion}](https://github.com/openrewrite/rewrite-gradle-plugin/releases/tag/v${gradlePluginVersion})" + writeln( + """ + # Latest versions of every OpenRewrite module + + OpenRewrite's modules are published to [Maven Central](https://search.maven.org/search?q=org.openrewrite). + Each time a release is made, a bill of materials artifact is also published to correctly align and manage the versions of all published artifacts. + The Gradle plugin is published to the [Gradle Plugin Portal](https://plugins.gradle.org/plugin/org.openrewrite.rewrite). + + It is highly recommended that developers use the [rewrite-recipe-bom](https://github.com/openrewrite/rewrite-recipe-bom) + to align the versions of Rewrite's modules to ensure compatibility. + The use of the "bill of materials" means that a developer will only need to specify explicit versions of the BOM and the build plugins: + + | Module | Version | + |-----------------------------------------------------------------------------------------------------------------------| ---------- | + | [**org.openrewrite.recipe:rewrite-recipe-bom**](https://github.com/openrewrite/rewrite-recipe-bom) | **${bomLink}** | + | [**org.openrewrite:rewrite-maven-plugin**](https://github.com/openrewrite/rewrite-maven-plugin) | **${mavenLink}** | + | [**org.openrewrite:rewrite-gradle-plugin**](https://github.com/openrewrite/rewrite-gradle-plugin) | **${gradleLink}** | + """.trimIndent() + ) + for (recipeOrigin in recipeOrigins.values) { + val repoLink = "[${recipeOrigin.groupId}:${recipeOrigin.artifactId}](${recipeOrigin.githubUrl()})" + val releaseLink = + "[${recipeOrigin.version}](${recipeOrigin.githubUrl()}/releases/tag/v${recipeOrigin.version})" + writeln("| ${repoLink.padEnd(117)} | ${releaseLink} |") + } + } + } + private fun getNewArtifacts( markdownArtifacts: TreeMap, oldArtifacts: TreeMap, @@ -490,15 +503,15 @@ class RecipeMarkdownGenerator : Runnable { if (deployType == "snapshot") { changelog.appendText("# Snapshot ($formatted)") - changelog.appendText("\n\n{% hint style=\"info\" %}") + changelog.appendText("\n\n:::info") changelog.appendText("\nWant to learn how to use snapshot versions in your project? Check out our [snapshot version guide](/reference/snapshot-instructions.md).") - changelog.appendText("\n{% endhint %}\n\n") + changelog.appendText("\n:::\n\n") } else { changelog.appendText("# $rewriteBomVersion release ($formatted)") - changelog.appendText("\n\n{% hint style=\"info\" %}") + changelog.appendText("\n\n:::info") changelog.appendText("\nThis changelog only shows what recipes have been added, removed, or changed. OpenRewrite may do releases that do not include these types of changes. To see these changes, please go to the [releases page](https://github.com/openrewrite/rewrite/releases).") - changelog.appendText("\n{% endhint %}\n\n") + changelog.appendText("\n:::\n\n") } // An example of what the changelog could look like after the below statements can be found here: @@ -706,55 +719,23 @@ class RecipeMarkdownGenerator : Runnable { descriptor.displayName.replace("`", "") } - /** - * Produce the snippet for this category to be fitted into Gitbook's SUMMARY.md, which provides the index - * that makes markdown documents accessible through gitbook's interface - */ - fun summarySnippet(indentationDepth: Int): String { - val indentBuilder = StringBuilder(" ") - for (i in 0 until indentationDepth) { - indentBuilder.append(" ") - } - val indent = indentBuilder.toString() - val result = StringBuilder() - - if (path == "") { - // Recipes that don't have a path are part of the "core" set of recipes - result.appendLine("$indent* [Core](reference/recipes/core.md)") - } else { - // Some nested recipes have a `github` path which gets converted into `Github` when it should be `GitHub`. - if (displayName == "Github") { - displayName = "GitHub" - } - - result.appendLine("$indent* [$displayName](reference/recipes/$path/README.md)") - } - - for (recipe in recipes) { - // Section headings will display backticks, rather than rendering as code. Omit them so it doesn't look terrible - result.appendLine( - "$indent * [${ - recipe.displayName.replace( - "`", - "" - ) - }](${getRecipeRelativePath(recipe)}.md)" - ) - } - - for (category in subcategories.sortedBy { it.simpleName }) { - result.append(category.summarySnippet(indentationDepth + 1)) - } - - return result.toString() - } - /** * Produce the contents of the README.md file for this category. */ private fun categoryIndex(): String { return StringBuilder().apply { - appendLine("# $displayName") + // Docusaurus gets confused when parsing C# as the sidebar title. We need to surround it in backticks + // so it displays correctly. + if (displayName == "C#") { + appendLine("# `C#`") + // Ai is not capitalized by default - so let's switch it to be AI + } else if (displayName == "Ai") { + appendLine("# AI") + } + else { + appendLine("# $displayName") + } + // While the description is not _supposed_ to be nullable it has happened before @Suppress("SENSELESS_COMPARISON") if (descriptor != null && descriptor.description != null) { @@ -771,7 +752,7 @@ class RecipeMarkdownGenerator : Runnable { appendLine("## Categories") appendLine() for (subcategory in subcategories) { - appendLine("* [${subcategory.displayName}](/reference/recipes/${subcategory.path})") + appendLine("* [${subcategory.displayName}](/recipes/${subcategory.path})") } appendLine() } @@ -795,11 +776,27 @@ class RecipeMarkdownGenerator : Runnable { appendLine() for (recipe in compositeRecipes) { - val recipeSimpleName = recipe.name.substring(recipe.name.lastIndexOf('.') + 1).lowercase() + var recipeSimpleName = recipe.name.substring(recipe.name.lastIndexOf('.') + 1).lowercase() + val formattedDisplayName = recipe.displayName + .replace("