Ver código fonte

repurpose 5.7.x branch to provide local docs build

* remove unused workflows, scripts, and configuration (now handled by docs-build branch)
* upgrade Antora to 3.1 (and Node.js to 16)
* tune playbook settings
* reconfigure docs build for local build only
* add patch to support using linked worktree as Antora content source
* remove Antora extensions not needed for local builds
Dan Allen 3 anos atrás
pai
commit
3e42119f84

+ 0 - 20
.github/actions/algolia-config.json

@@ -1,20 +0,0 @@
-{
-  "index_name": "security-docs",
-  "start_urls": [
-    "https://docs.spring.io/spring-security/reference/"
-  ],
-  "selectors": {
-    "lvl0": {
-      "selector": "//nav[@class='crumbs']//li[@class='crumb'][last()-1]",
-      "type": "xpath",
-      "global": true,
-      "default_value": "Home"
-    },
-    "lvl1": ".doc h1",
-    "lvl2": ".doc h2",
-    "lvl3": ".doc h3",
-    "lvl4": ".doc h4",
-    "text": ".doc p, .doc td.content, .doc th.tableblock"
-  }
-}
-

+ 0 - 20
.github/actions/algolia-deploy.sh

@@ -1,20 +0,0 @@
-#!/bin/bash
-
-HOST="$1"
-HOST_PATH="$2"
-SSH_PRIVATE_KEY="$3"
-SSH_KNOWN_HOST="$4"
-
-
-if [ "$#" -ne 4 ]; then
-  echo -e "not enough arguments USAGE:\n\n$0 \$HOST \$HOST_PATH \$SSH_PRIVATE_KEY \$SSH_KNOWN_HOSTS \n\n" >&2
-  exit 1
-fi
-
-# Use a non-default path to avoid overriding when testing locally
-SSH_PRIVATE_KEY_PATH=~/.ssh/github-actions-docs
-install -m 600 -D /dev/null "$SSH_PRIVATE_KEY_PATH"
-echo "$SSH_PRIVATE_KEY" > "$SSH_PRIVATE_KEY_PATH"
-echo "$SSH_KNOWN_HOST" > ~/.ssh/known_hosts
-rsync --delete -avze "ssh -i $SSH_PRIVATE_KEY_PATH" docs/build/site/ "$HOST:$HOST_PATH"
-rm -f "$SSH_PRIVATE_KEY_PATH"

+ 0 - 21
.github/actions/algolia-docsearch-scraper.sh

@@ -1,21 +0,0 @@
-#!/bin/bash
-
-###
-# Docs
-# config.json https://docsearch.algolia.com/docs/config-file
-# Run the crawler https://docsearch.algolia.com/docs/run-your-own/#run-the-crawl-from-the-docker-image
-
-### USAGE
-if [ "$#" -ne 3 ]; then
-  echo -e "not enough arguments USAGE:\n\n$0 \$ALGOLIA_APPLICATION_ID \$ALGOLIA_API_KEY \$CONFIG_FILE\n\n" >&2
-  exit 1
-fi
-
-# Script Parameters
-APPLICATION_ID=$1
-API_KEY=$2
-CONFIG_FILE=$3
-
-#### Script
-script_dir=$(dirname $0)
-docker run -e "APPLICATION_ID=$APPLICATION_ID" -e "API_KEY=$API_KEY" -e "CONFIG=$(cat $CONFIG_FILE | jq -r tostring)" algolia/docsearch-scraper

+ 0 - 20
.github/workflows/algolia-index.yml

@@ -1,20 +0,0 @@
-name: Update Algolia Index
-
-on:
-  schedule:
-    - cron: '0 10 * * *' # Once per day at 10am UTC
-  workflow_dispatch: # Manual trigger
-
-permissions:
-  contents: read
-
-jobs:
-  update:
-    name: Update Algolia Index
-    runs-on: ubuntu-latest
-    if: ${{ github.repository == 'spring-projects/spring-security' }}
-    steps:
-      - name: Checkout Source
-        uses: actions/checkout@v2
-      - name: Update Index
-        run: ${GITHUB_WORKSPACE}/.github/actions/algolia-docsearch-scraper.sh "${{ secrets.ALGOLIA_APPLICATION_ID }}" "${{ secrets.ALGOLIA_WRITE_API_KEY }}" "${GITHUB_WORKSPACE}/.github/actions/algolia-config.json"

+ 0 - 34
.github/workflows/deploy-reference.yml

@@ -1,34 +0,0 @@
-name: Build & Deploy Reference
-
-on:
-  repository_dispatch:
-    types: request-build-reference
-  schedule:
-    - cron: '0 10 * * *' # Once per day at 10am UTC
-  workflow_dispatch: # Manual trigger
-
-permissions:
-  contents: read
-
-jobs:
-  deploy:
-    name: deploy
-    runs-on: ubuntu-latest
-    if: ${{ github.repository == 'spring-projects/spring-security' }}
-    steps:
-      - uses: actions/checkout@v2
-      - name: Set up gradle
-        uses: spring-io/spring-gradle-build-action@v1
-        with:
-          java-version: '11'
-          distribution: 'adopt'
-      - name: Cleanup Gradle Cache
-        # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
-        # Restoring these files from a GitHub Actions cache might cause problems for future builds.
-        run: |
-          rm -f /home/runner/.gradle/caches/modules-2/modules-2.lock
-          rm -f /home/runner/.gradle/caches/modules-2/gc.properties
-      - name: Build with Gradle
-        run: ./gradlew :spring-security-docs:antora --stacktrace
-      - name: Deploy
-        run: ${GITHUB_WORKSPACE}/.github/actions/algolia-deploy.sh "${{ secrets.DOCS_USERNAME }}@${{ secrets.DOCS_HOST }}" "/opt/www/domains/spring.io/docs/htdocs/spring-security/reference/" "${{ secrets.DOCS_SSH_KEY }}" "${{ secrets.DOCS_SSH_HOST_KEY }}"

+ 2 - 0
docs/.gitignore

@@ -0,0 +1,2 @@
+/package-lock.json
+/node_modules/

+ 53 - 0
docs/antora-linked-worktree-patch.js

@@ -0,0 +1,53 @@
+'use strict'
+
+/* Copyright (c) 2002-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+const { promises: fsp } = require('fs')
+const ospath = require('path')
+
+/**
+ * Rewrites local content sources to support the use of linked worktrees.
+ *
+ * @author Dan Allen <dan@opendevise.com>
+ */
+module.exports.register = function () {
+  this.once('playbookBuilt', async ({ playbook }) => {
+    const expandPath = this.require('@antora/expand-path-helper')
+    for (const contentSource of playbook.content.sources) {
+      const { url, branches } = contentSource
+      if (url.charAt() !== '.') continue
+      const absdir = expandPath(url, { dot: playbook.dir })
+      const gitfile = ospath.join(absdir, '.git')
+      if (await fsp.stat(gitfile).then((stat) => !stat.isDirectory(), () => false)) {
+        const worktreeGitdir = await fsp.readFile(gitfile, 'utf8')
+          .then((contents) => contents.trimRight().substr(8))
+        const worktreeBranch = await fsp.readFile(ospath.join(worktreeGitdir, 'HEAD'), 'utf8')
+          .then((contents) => contents.trimRight().replace(/^ref: (?:refs\/heads\/)?/, ''))
+        const reldir = ospath.relative(
+          playbook.dir,
+          await fsp.readFile(ospath.join(worktreeGitdir, 'commondir'), 'utf8')
+            .then((contents) => {
+              const gitdir = ospath.join(worktreeGitdir, contents.trimRight())
+              return ospath.basename(gitdir) === '.git' ? ospath.dirname(gitdir) : gitdir
+            })
+        )
+        contentSource.url = reldir ? `.${ospath.sep}${reldir}` : '.'
+        if (!branches) continue
+        contentSource.branches = (branches.constructor === Array ? branches : [branches])
+          .map((pattern) => pattern.replaceAll('HEAD', worktreeBranch))
+      }
+    }
+  })
+}

+ 0 - 27
docs/antora-playbook.yml

@@ -1,27 +0,0 @@
-site:
-  title: Spring Security
-  url: https://docs.spring.io/spring-security/reference/
-asciidoc:
-  attributes:
-    page-pagination: true
-content:
-  sources:
-    - url: https://github.com/spring-io/spring-generated-docs
-      branches: [spring-projects/spring-security/*]
-    - url: https://github.com/spring-projects/spring-security
-      branches: [main,5.6.x,5.7.x]
-      tags: ['5.6.*','!5.6.0-M*','5.7.*','6.0.*']
-      start_path: docs
-urls:
-  latest_version_segment_strategy: redirect:to
-  latest_version_segment: ''
-  redirect_facility: httpd
-ui:
-  bundle:
-    url: https://github.com/spring-io/antora-ui-spring/releases/download/latest/ui-bundle.zip
-    snapshot: true
-
-antora:
-  extensions:
-    - require: ./antora/extensions/version-fix.js
-    - require: ./antora/extensions/major-minor-segment.js

+ 3 - 3
docs/antora.yml

@@ -1,3 +1,3 @@
-'name': 'ROOT'
-'prerelease': '-SNAPSHOT'
-'version': '5.7.4'
+name: 'ROOT'
+version: 5.7.4
+prerelease: '-SNAPSHOT'

+ 0 - 200
docs/antora/extensions/major-minor-segment.js

@@ -1,200 +0,0 @@
-// https://gitlab.com/antora/antora/-/issues/132#note_712132072
-'use strict'
-
-const { posix: path } = require('path')
-
-module.exports.register = function({ config }) {
-    this.on('contentClassified', ({ contentCatalog }) => {
-        contentCatalog.getComponents().forEach(component => {
-            const componentName = component.name;
-            const generationToVersion = new Map();
-            component.versions.forEach(version => {
-                const generation = getGeneration(version.version);
-                const original = generationToVersion.get(generation);
-                if (original === undefined || (original.prerelease && !version.prerelease)) {
-                    generationToVersion.set(generation, version);
-                }
-            });
-
-            const versionToGeneration = Array.from(generationToVersion.entries()).reduce((acc, entry) => {
-                const [ generation, version ] = entry;
-                acc.set(version.version, generation);
-                return acc;
-            }, new Map());
-
-            contentCatalog.findBy({ component: componentName }).forEach((file) => {
-                const candidateVersion = file.src.version;
-                if (versionToGeneration.has(candidateVersion)) {
-                    const generation = versionToGeneration.get(candidateVersion);
-                    if (file.out) {
-                        if (file.out) {
-                            file.out.dirname = file.out.dirname.replace(candidateVersion, generation)
-                            file.out.path = file.out.path.replace(candidateVersion, generation);
-                        }
-                    }
-                    if (file.pub) {
-                        file.pub.url = file.pub.url.replace(candidateVersion, generation)
-                    }
-                }
-            });
-            versionToGeneration.forEach((generation, mappedVersion) => {
-                contentCatalog.getComponent(componentName).versions.filter(version => version.version === mappedVersion).forEach((version) => {
-                    version.url = version.url.replace(mappedVersion, generation);
-                })
-                const symbolicVersionAlias = createSymbolicVersionAlias(
-                    componentName,
-                    mappedVersion,
-                    generation,
-                    'redirect:to'
-                )
-                symbolicVersionAlias.src.version = generation;
-                contentCatalog.addFile(symbolicVersionAlias);
-            });
-        })
-    })
-}
-
-function createSymbolicVersionAlias (component, version, symbolicVersionSegment, strategy) {
-    if (symbolicVersionSegment == null || symbolicVersionSegment === version) return
-    const family = 'alias'
-    const baseVersionAliasSrc = { component, module: 'ROOT', family, relative: '', basename: '', stem: '', extname: '' }
-    const symbolicVersionAliasSrc = Object.assign({}, baseVersionAliasSrc, { version: symbolicVersionSegment })
-    const symbolicVersionAlias = {
-        src: symbolicVersionAliasSrc,
-        pub: computePub(
-            symbolicVersionAliasSrc,
-            computeOut(symbolicVersionAliasSrc, family, symbolicVersionSegment),
-            family
-        ),
-    }
-    const originalVersionAliasSrc = Object.assign({}, baseVersionAliasSrc, { version })
-    const originalVersionSegment = computeVersionSegment(component, version, 'original')
-    const originalVersionAlias = {
-        src: originalVersionAliasSrc,
-        pub: computePub(
-            originalVersionAliasSrc,
-            computeOut(originalVersionAliasSrc, family, originalVersionSegment),
-            family
-        ),
-    }
-    if (strategy === 'redirect:to') {
-        originalVersionAlias.out = undefined
-        originalVersionAlias.rel = symbolicVersionAlias
-        return originalVersionAlias
-    } else {
-        symbolicVersionAlias.out = undefined
-        symbolicVersionAlias.rel = originalVersionAlias
-        return symbolicVersionAlias
-    }
-}
-
-
-function computeOut (src, family, version, htmlUrlExtensionStyle) {
-    let { component, module: module_, basename, extname, relative, stem } = src
-    if (module_ === 'ROOT') module_ = ''
-    let indexifyPathSegment = ''
-    let familyPathSegment = ''
-
-    if (family === 'page') {
-        if (stem !== 'index' && htmlUrlExtensionStyle === 'indexify') {
-            basename = 'index.html'
-            indexifyPathSegment = stem
-        } else if (extname === '.adoc') {
-            basename = stem + '.html'
-        }
-    } else if (family === 'image') {
-        familyPathSegment = '_images'
-    } else if (family === 'attachment') {
-        familyPathSegment = '_attachments'
-    }
-    const modulePath = path.join(component, version, module_)
-    const dirname = path.join(modulePath, familyPathSegment, path.dirname(relative), indexifyPathSegment)
-    const path_ = path.join(dirname, basename)
-    const moduleRootPath = path.relative(dirname, modulePath) || '.'
-    const rootPath = path.relative(dirname, '') || '.'
-
-    return { dirname, basename, path: path_, moduleRootPath, rootPath }
-}
-
-function computePub (src, out, family, version, htmlUrlExtensionStyle) {
-    const pub = {}
-    let url
-    if (family === 'nav') {
-        const urlSegments = version ? [src.component, version] : [src.component]
-        if (src.module && src.module !== 'ROOT') urlSegments.push(src.module)
-        // an artificial URL used for resolving page references in navigation model
-        url = '/' + urlSegments.join('/') + '/'
-        pub.moduleRootPath = '.'
-    } else if (family === 'page') {
-        const urlSegments = out.path.split('/')
-        const lastUrlSegmentIdx = urlSegments.length - 1
-        if (htmlUrlExtensionStyle === 'drop') {
-            // drop just the .html extension or, if the filename is index.html, the whole segment
-            const lastUrlSegment = urlSegments[lastUrlSegmentIdx]
-            urlSegments[lastUrlSegmentIdx] =
-                lastUrlSegment === 'index.html' ? '' : lastUrlSegment.substr(0, lastUrlSegment.length - 5)
-        } else if (htmlUrlExtensionStyle === 'indexify') {
-            urlSegments[lastUrlSegmentIdx] = ''
-        }
-        url = '/' + urlSegments.join('/')
-    } else {
-        url = '/' + out.path
-        if (family === 'alias' && !src.relative.length) pub.splat = true
-    }
-
-    pub.url = ~url.indexOf(' ') ? url.replace(SPACE_RX, '%20') : url
-
-    if (out) {
-        pub.moduleRootPath = out.moduleRootPath
-        pub.rootPath = out.rootPath
-    }
-
-    return pub
-}
-
-function computeVersionSegment (name, version, mode) {
-    if (mode === 'original') return !version || version === 'master' ? '' : version
-    const strategy = this.latestVersionUrlSegmentStrategy
-    // NOTE: special exception; revisit in Antora 3
-    if (!version || version === 'master') {
-        if (mode !== 'alias') return ''
-        if (strategy === 'redirect:to') return
-    }
-    if (strategy === 'redirect:to' || strategy === (mode === 'alias' ? 'redirect:from' : 'replace')) {
-        const component = this.getComponent(name)
-        const componentVersion = component && this.getComponentVersion(component, version)
-        if (componentVersion) {
-            const segment =
-                componentVersion === component.latest
-                    ? this.latestVersionUrlSegment
-                    : componentVersion === component.latestPrerelease
-                        ? this.latestPrereleaseVersionUrlSegment
-                        : undefined
-            return segment == null ? version : segment
-        }
-    }
-    return version
-}
-
-function getGeneration(version) {
-    if (!version) return version;
-    const firstIndex = version.indexOf('.')
-    if (firstIndex < 0) {
-        return version;
-    }
-    const secondIndex = version.indexOf('.', firstIndex + 1);
-    const result = version.substr(0, secondIndex);
-    return result;
-}
-
-function out(args) {
-    console.log(JSON.stringify(args, no_data, 2));
-}
-
-
-function no_data(key, value) {
-    if (key == "data" || key == "files") {
-        return value ? "__data__" : value;
-    }
-    return value;
-}

+ 0 - 40
docs/antora/extensions/root-component-name.js

@@ -1,40 +0,0 @@
-// https://gitlab.com/antora/antora/-/issues/132#note_712132072
-'use strict'
-
-const { posix: path } = require('path')
-
-module.exports.register = (pipeline, { config }) => {
-    pipeline.on('contentClassified', ({ contentCatalog }) => {
-        const rootComponentName = config.rootComponentName || 'ROOT'
-        const rootComponentNameLength = rootComponentName.length
-        contentCatalog.findBy({ component: rootComponentName }).forEach((file) => {
-            if (file.out) {
-                file.out.dirname = file.out.dirname.substr(rootComponentNameLength)
-                file.out.path = file.out.path.substr(rootComponentNameLength + 1)
-                file.out.rootPath = fixPath(file.out.rootPath)
-            }
-            if (file.pub) {
-                file.pub.url = file.pub.url.substr(rootComponentNameLength + 1)
-                if (file.pub.rootPath) {
-                    file.pub.rootPath = fixPath(file.pub.rootPath)
-                }
-            }
-            if (file.rel) {
-                if (file.rel.pub) {
-                    file.rel.pub.url = file.rel.pub.url.substr(rootComponentNameLength + 1)
-                    file.rel.pub.rootPath = fixPath(file.rel.pub.rootPath);
-                }
-            }
-        })
-        const rootComponent = contentCatalog.getComponent(rootComponentName)
-        rootComponent?.versions?.forEach((version) => {
-            version.url = version.url.substr(rootComponentName.length + 1)
-        })
-        // const siteStartPage = contentCatalog.getById({ component: '', version: '', module: '', family: 'alias', relative: 'index.adoc' })
-        // if (siteStartPage) delete siteStartPage.out
-    })
-
-    function fixPath(path) {
-        return path.split('/').slice(1).join('/') || '.'
-    }
-}

+ 0 - 35
docs/antora/extensions/version-fix.js

@@ -1,35 +0,0 @@
-// https://gitlab.com/antora/antora/-/issues/132#note_712132072
-'use strict'
-
-
-module.exports.register = function({ config }) {
-    this.on('contentAggregated', ({ contentAggregate }) => {
-        contentAggregate.forEach(aggregate => {
-            if (aggregate.name === "" && aggregate.displayVersion === 5.6) {
-                aggregate.name = "ROOT";
-                aggregate.version = "5.6.0-RC1"
-                aggregate.startPage = "ROOT:index.adoc"
-                aggregate.displayVersion = `${aggregate.version}`
-                delete aggregate.prerelease
-            }
-            if (aggregate.version === "5.6.1" &&
-                    aggregate.prerelease == "-SNAPSHOT") {
-                aggregate.version = "5.6.1"
-                aggregate.displayVersion = `${aggregate.version}`
-                delete aggregate.prerelease
-            }
-        })
-    })
-}
-
-function out(args) {
-    console.log(JSON.stringify(args, no_data, 2));
-}
-
-
-function no_data(key, value) {
-    if (key == "data" || key == "files") {
-        return value ? "__data__" : value;
-    }
-    return value;
-}

+ 16 - 16
docs/local-antora-playbook.yml

@@ -1,26 +1,26 @@
+# The purpose of this Antora playbook is to generate a preview of the docs in the current branch.
+antora:
+  extensions:
+  - ./antora-linked-worktree-patch.js
+runtime:
+  log:
+    format: pretty
 site:
   title: Spring Security
-  url: https://docs.spring.io/spring-security/reference/
-asciidoc:
-  attributes:
-    page-pagination: true
+  url: https://docs.spring.io/spring-security/reference
 content:
   sources:
-    - url: https://github.com/spring-io/spring-generated-docs
-      branches: [spring-projects/spring-security/5.7.x]
-    - url: ../
-      branches: HEAD
-      start_path: docs
+  - url: ./..
+    branches: HEAD
+    start_paths: [docs, 'docs/build/generateAntora*']
+    worktrees: true
+asciidoc:
+  attributes:
+    page-pagination: ''
+    hide-uri-scheme: '@'
 urls:
-  latest_version_segment_strategy: redirect:to
   latest_version_segment: ''
-  redirect_facility: httpd
 ui:
   bundle:
     url: https://github.com/spring-io/antora-ui-spring/releases/download/latest/ui-bundle.zip
     snapshot: true
-
-antora:
-  extensions:
-    - require: ./antora/extensions/version-fix.js
-    - require: ./antora/extensions/major-minor-segment.js

+ 8 - 0
docs/package.json

@@ -0,0 +1,8 @@
+{
+  "name": "spring-security-docs-antora",
+  "private": true,
+  "dependencies": {
+    "@antora/cli": "^3.1.0",
+    "@antora/site-generator-default": "^3.1.0"
+  }
+}

+ 11 - 7
docs/spring-security-docs.gradle

@@ -6,16 +6,22 @@ plugins {
 apply plugin: 'io.spring.convention.docs'
 apply plugin: 'java'
 
+node {
+	version = "16.17.0"
+}
+
 antora {
-	antoraVersion = "3.0.0-alpha.8"
-	arguments = ["--fetch"]
+	antoraVersion = "3.1.0"
+	playbookFile = file("local-antora-playbook.yml")
+	arguments = ["--clean", "--stacktrace"]
 }
 
 tasks.antora {
+	dependsOn "generateAntora"
 	environment = [
-			"ALGOLIA_API_KEY" : "82c7ead946afbac3cf98c32446154691",
-			"ALGOLIA_APP_ID" : "244V8V9FGG",
-			"ALGOLIA_INDEX_NAME" : "security-docs"
+		"ALGOLIA_API_KEY" : "82c7ead946afbac3cf98c32446154691",
+		"ALGOLIA_APP_ID" : "244V8V9FGG",
+		"ALGOLIA_INDEX_NAME" : "security-docs"
 	]
 }
 
@@ -64,8 +70,6 @@ ${ymlVersions}
 	}
 }
 
-
-
 dependencies {
 	testImplementation platform(project(":spring-security-dependencies"))
 	testImplementation "com.unboundid:unboundid-ldapsdk"

+ 0 - 17
local-antora-playbook.yml

@@ -1,17 +0,0 @@
-site:
-  title: Spring Security
-  start_page: security::index.adoc
-asciidoc:
-  attributes:
-    page-pagination: true
-content:
-  sources:
-    - url: ./
-      branches: [HEAD]
-      start_path: docs
-    - url: ../../rwinch/spring-security-docs-generated
-      branches: [HEAD]
-ui:
-  bundle:
-    url: https://github.com/rwinch/antora-ui-spring/releases/download/latest/ui-bundle.zip
-    snapshot: true