From 986849a8e4dd20a68f33b36adb86d449ba5e37f6 Mon Sep 17 00:00:00 2001 From: Sean Arms <67096+lesserwhirls@users.noreply.github.com> Date: Thu, 6 Feb 2025 10:36:53 -0700 Subject: [PATCH] Build docs using docker Migrate from jruby-based jekyll build to docker-based build. Configure a jenkins pipeline for doc build --- build.gradle | 3 - docs/.gitignore | 3 +- docs/README.md | 7 ++ .../src/site/pages/thredds/WmsConfig.md | 2 +- docs/build.gradle | 70 ++++++++++---- .../src/site/pages/thredds/WmsConfig.md | 2 +- gradle/any/shared-mvn-coords.gradle | 1 - project-files/jenkins/pipelines/docs | 94 +++++++++++++++++++ 8 files changed, 159 insertions(+), 23 deletions(-) create mode 100644 project-files/jenkins/pipelines/docs diff --git a/build.gradle b/build.gradle index 58ddee2ab4..fccc19d22a 100644 --- a/build.gradle +++ b/build.gradle @@ -26,8 +26,6 @@ buildscript { filter { includeModule 'com.burgstaller', 'okhttp-digest' includeModule 'org.ysb33r.gradle', 'grolifant' - includeModule 'edu.ucar.unidata.site', 'jekyll-plugin' - includeModule 'edu.ucar.unidata.site', 'jekyll-gems' includeModule 'edu.ucar.unidata', 'unidata-nexus-gradle' } } @@ -40,7 +38,6 @@ buildscript { classpath buildPlugins.spotless classpath buildPlugins.protobuf classpath buildPlugins.nexus - classpath buildPlugins.jekyll classpath buildPlugins.depcheck } } diff --git a/docs/.gitignore b/docs/.gitignore index e3e4bd608e..f32c3e5b74 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,3 +1,4 @@ # copies of shared files used by documentation build **/_data/topnav.yml -**/sitemap*.xml \ No newline at end of file +**/sitemap*.xml +*/.jekyll-cache diff --git a/docs/README.md b/docs/README.md index 8cdf41f67a..46642377ac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,6 +2,10 @@ All gradle commands shown below must be run from the top level of the TDS repository. +## Requirements + +In addition to Java, Docker is now required for building the TDS docsets. + ## Jekyll-based documentation All docsets are published in the Nexus raw repository `docs-tds`. @@ -32,6 +36,9 @@ For more information, see [shared/README.md](shared/README.md). * Serve * same as `build*` tasks above, but using `serve*` (e.g. `./gradlew :docs:serveUserGuide`) + * useful for live editing, as changes to .md files will be picked up and content regenerated on the fly + * note that only one docset can be served at a time + * when finished serving a doc set, run `./gradlew :docs:stopServe` to shutdown the docker container hosting the server * Build all Jekyll-based sites (shortcut for building all jekyll-based documentation sets) * `./gradlew :docs:buildAllJekyllSites` diff --git a/docs/adminguide/src/site/pages/thredds/WmsConfig.md b/docs/adminguide/src/site/pages/thredds/WmsConfig.md index 9d1500025a..8e5aef43b2 100644 --- a/docs/adminguide/src/site/pages/thredds/WmsConfig.md +++ b/docs/adminguide/src/site/pages/thredds/WmsConfig.md @@ -10,7 +10,7 @@ Several properties related to the generation of images from the WMS service can By default, this file is located in the `${tds.content.root.path}/thredds` directory. An example `wmsConfig.xml` file is shipped with the TDS, which looks like: -{% capture rmd %}{% includefile ../tds/src/main/webapp/WEB-INF/altContent/startup/wmsConfig.xml %}{% endcapture %} +{% capture rmd %}{% includefile ../../../../tds/src/main/webapp/WEB-INF/altContent/startup/wmsConfig.xml %}{% endcapture %} ~~~xml {{ rmd }} diff --git a/docs/build.gradle b/docs/build.gradle index 512f608da3..6c0d46da95 100644 --- a/docs/build.gradle +++ b/docs/build.gradle @@ -1,18 +1,12 @@ plugins { id 'base' - id 'edu.ucar.unidata.site.jekyll' } -// disable tasks added by the jekyll plugin...we need custom tasks, one for each docset -buildJekyllSite.enabled(false) -serveJekyllSite.enabled(false) - apply from: "${rootDir}/gradle/any/properties.gradle" apply from: "${projectDir}/helpers.gradle" import edu.ucar.build.publishing.tasks.PublishToRawRepoTask import edu.ucar.build.publishing.tasks.DeleteFromNexusTask -import edu.ucar.unidata.site.jekyll.tasks.ServeTask //////////////////////// // Jekyll Sites Build // @@ -59,31 +53,75 @@ tasks.register(buildAllJekyllSitesTaskName) { description = 'Build all jekyll sites.' } +String docTheme = "unidata-jekyll-docs:0.0.4" + +boolean isGitHub = System.getenv('GITHUB_ACTIONS') as boolean +String imageBaseUrl = "docker.unidata.ucar.edu" +if (isGitHub) { + imageBaseUrl = "ghcr.io/unidata" +} +String dockerImage = "${imageBaseUrl}/${docTheme}" + +class NullOutputStream extends OutputStream { + @Override + void write(int b) throws IOException {} +} + // setup build and publish tasks associated with each individual documentation set docsets.each { docset -> def partialTaskName = makeUpperCamelCase(docset) - def buildTask = tasks.register("build${partialTaskName}", edu.ucar.unidata.site.jekyll.tasks.BuildTask) { + Provider siteBuildDir = layout.buildDirectory.dir("site/${docset}") + def buildTask = tasks.register("build${partialTaskName}", Exec) { group 'documentation-set' - script = 'jekyll' description "Build ${docset} jekyll site." - sourceDirectory.set(layout.projectDirectory.dir("${docset}/src/site")) - destinationDirectory.set(layout.buildDirectory.dir("site/${docset}/")) - dependsOn tasks.named('unpackGemJar'), copySharedJekyllFilesTask + ConfigurableFileTree buildDocInputs = fileTree("./${docset}/src/site") + buildDocInputs.exclude(".jekyll-cache") + inputs.files(buildDocInputs) + outputs.dir(siteBuildDir) + commandLine("docker", "run", "--rm", + "-e", "SRC_DIR=/tds/docs/${docset}/src/site", + "-v", "${rootDir}:/tds", + "-v", "./${relativePath(siteBuildDir.get().toString())}:/site", + dockerImage, "build") + dependsOn copySharedJekyllFilesTask } - tasks.register("serve${partialTaskName}", ServeTask) { + tasks.register("serve${partialTaskName}", Exec) { group 'documentation-set' - script = 'jekyll' description "Serve $docset jekyll site." - sourceDirectory.set(layout.projectDirectory.dir("${docset}/src/site")) - destinationDirectory.set(layout.buildDirectory.dir("site/${docset}/")) - dependsOn tasks.named('unpackGemJar') + commandLine("docker", "run", "--rm", "-d", + "--name", "tds-docs-server", + "-e", "SRC_DIR=/tds/docs/${docset}/src/site", + "-v", "${rootDir}:/tds", + "-p", "4005:4005", + dockerImage, "serve", "--livereload") + standardOutput = new NullOutputStream() + dependsOn copySharedJekyllFilesTask + doLast { + String msg = "TDS ${docset} available at http://localhost:4005" + String bannerBorder = new String(new char[msg.length() + 4]).replace("\0", "#"); + println() + println(bannerBorder) + println("# $msg #") + println(bannerBorder) + println() + } } // register tasks with the aggregator build task tasks.named(buildAllJekyllSitesTaskName).configure({dependsOn buildTask}) } +tasks.register("stopServe", Exec) { + group = "documentation-set" + description = "Stop the local server used while live editing a tds documentation set." + commandLine("docker", "stop", "tds-docs-server") + docsets.each { docset -> + delete("${projectDir}/${docset}/src/site/Gemfile") + delete("${projectDir}/${docset}/src/site/Gemfile.lock") + } +} + ///////////////////////////////////////////// // Nexus Repository Publication Management // ///////////////////////////////////////////// diff --git a/docs/userguide/src/site/pages/thredds/WmsConfig.md b/docs/userguide/src/site/pages/thredds/WmsConfig.md index 4bb69dc799..816a9ed73a 100644 --- a/docs/userguide/src/site/pages/thredds/WmsConfig.md +++ b/docs/userguide/src/site/pages/thredds/WmsConfig.md @@ -10,7 +10,7 @@ Several properties related to the generation of images from the WMS service can By default, this file is located in the `${tds.content.root.path}/thredds` directory. An example `wmsConfig.xml` file is shipped with the TDS, which looks like: -{% capture rmd %}{% includefile ../tds/src/main/webapp/WEB-INF/altContent/startup/wmsConfig.xml %}{% endcapture %} +{% capture rmd %}{% includefile ../../../../tds/src/main/webapp/WEB-INF/altContent/startup/wmsConfig.xml %}{% endcapture %} ~~~xml {{ rmd }} diff --git a/gradle/any/shared-mvn-coords.gradle b/gradle/any/shared-mvn-coords.gradle index 8e02bdb0fb..c9a99ecd34 100644 --- a/gradle/any/shared-mvn-coords.gradle +++ b/gradle/any/shared-mvn-coords.gradle @@ -11,7 +11,6 @@ ext { buildPlugins.spotless = 'com.diffplug.spotless:spotless-plugin-gradle:4.5.1' buildPlugins.protobuf = 'com.google.protobuf:protobuf-gradle-plugin:0.8.18' buildPlugins.nexus = 'edu.ucar.unidata:unidata-nexus-gradle:0.0.1' - buildPlugins.jekyll = 'edu.ucar.unidata.site:jekyll-plugin:0.0.4' buildPlugins.depcheck = 'org.owasp:dependency-check-gradle:8.2.1' // slf4j version is declared in a place where we cannot use the tds-platform project to handle resolving versions diff --git a/project-files/jenkins/pipelines/docs b/project-files/jenkins/pipelines/docs new file mode 100644 index 0000000000..409bb51b95 --- /dev/null +++ b/project-files/jenkins/pipelines/docs @@ -0,0 +1,94 @@ +pipeline { + agent { label 'main' } + stages { + stage('Bootstrap documentation') { + agent { + docker { + image 'docker.unidata.ucar.edu/thredds-test-environment:latest' + // Run the container on the node specified at the + // top-level of the Pipeline, in the same workspace, + // rather than on a new node entirely: + reuseNode true + } + } + steps { + sh '''#!/bin/bash -l + select-java temurin 17 + ./gradlew :docs:copySharedJekyllFiles + ''' + } + } + stage('Build adminguide') { + steps { + sh '''docker run --rm \ + -e SRC_DIR=/tds/docs/adminguide/src/site \ + -e DOCS_UID=$(id -u) \ + -v .:/tds \ + -v ./docs/build/site/adminguide:/site \ + docker.unidata.ucar.edu/unidata-jekyll-docs:0.0.4 build + ''' + } + } + stage('Build devguide') { + steps { + sh '''docker run --rm \ + -e SRC_DIR=/tds/docs/devguide/src/site \ + -e DOCS_UID=$(id -u) \ + -v .:/tds \ + -v ./docs/build/site/devguide:/site \ + docker.unidata.ucar.edu/unidata-jekyll-docs:0.0.4 build + ''' + } + } + stage('Build quickstart') { + steps { + sh '''docker run --rm \ + -e SRC_DIR=/tds/docs/quickstart/src/site \ + -e DOCS_UID=$(id -u) \ + -v .:/tds \ + -v ./docs/build/site/quickstart:/site \ + docker.unidata.ucar.edu/unidata-jekyll-docs:0.0.4 build + ''' + } + } + stage('Build userguide') { + steps { + sh '''docker run --rm \ + -e SRC_DIR=/tds/docs/userguide/src/site \ + -e DOCS_UID=$(id -u) \ + -v .:/tds \ + -v ./docs/build/site/userguide:/site \ + docker.unidata.ucar.edu/unidata-jekyll-docs:0.0.4 build + ''' + } + } + stage('Publish documentation') { + agent { + docker { + image 'docker.unidata.ucar.edu/thredds-test-environment:latest' + // Run the container on the node specified at the + // top-level of the Pipeline, in the same workspace, + // rather than on a new node entirely: + reuseNode true + } + } + steps { + withCredentials([file(credentialsId: 'thredds_vault', variable: 'TV'), file(credentialsId: 'vault_pw', variable: 'AVP')]) { + sh '''#!/bin/bash -l + select-java temurin 17 + set +x + ./gradlew \ + -Pnexus.username=`get_pw NEXUS_USER` \ + -Pnexus.password=`get_pw NEXUS_PW` \ + -x :docs:buildAdminGuide \ + -x :docs:buildDevGuide \ + -x :docs:buildQuickstart \ + -x :docs:buildUserGuide \ + -x :docs:buildAllJekyllSites \ + :docs:publishAllJekyllSitesAsVersioned + ''' + } + } + } + } +} \ No newline at end of file