diff --git a/.github/actions/publish-docs.sh b/.github/actions/publish-docs.sh index 1267e56a10..0f46bfea71 100755 --- a/.github/actions/publish-docs.sh +++ b/.github/actions/publish-docs.sh @@ -1,5 +1,6 @@ #!/bin/bash +FROM=build/site HOST="$1" HOST_PATH="$2" SSH_PRIVATE_KEY="$3" @@ -13,10 +14,16 @@ fi ( set -e + set -f 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" build/site/ "$HOST:$HOST_PATH" + RSYNC_OPTS='-avz --delete' + if [ -n "$BUILD_REFNAME" ]; then + RSYNC_OPTS="-n $RSYNC_OPTS$(find $FROM -mindepth 1 -maxdepth 1 \! -name 404.html \! -name '.*' -type f -printf ' --include /%P')" + RSYNC_OPTS="$RSYNC_OPTS$(find $FROM -mindepth 1 -maxdepth 1 -type d \! -name _ -printf ' --include /%P --include /%P/**') --exclude **" + fi + rsync $RSYNC_OPTS -e "ssh -i $SSH_PRIVATE_KEY_PATH" $FROM/ "$HOST:$HOST_PATH" ) exit_code=$? diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 2e6a2647ef..8208b82edf 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -1,6 +1,10 @@ name: Deploy Docs on: workflow_dispatch: + inputs: + build-refname: + description: Enter git refname to build (e.g., 5.7.x). + required: false push: branches: docs-build permissions: read-all @@ -10,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 5 - name: Set Up Gradle @@ -24,6 +28,12 @@ jobs: run: | rm -f /home/runner/.gradle/caches/modules-2/modules-2.lock rm -f /home/runner/.gradle/caches/modules-2/gc.properties + - name: Set up refname build + if: github.event.inputs.build-refname + run: | + git fetch --depth 1 https://github.com/$GITHUB_REPOSITORY ${{ github.event.inputs.build-refname }} + echo BUILD_REFNAME=${{ github.event.inputs.build-refname }} >> $GITHUB_ENV + echo BUILD_VERSION=$(git cat-file --textconv FETCH_HEAD:gradle.properties | sed -n '/^version=/ { s/^version=//;p }') >> $GITHUB_ENV - name: Run Antora run: ./gradlew antora - name: Publish Docs diff --git a/antora-playbook.yml b/antora-playbook.yml index 85336f7f32..9d35817d7f 100644 --- a/antora-playbook.yml +++ b/antora-playbook.yml @@ -1,8 +1,10 @@ antora: extensions: + - ./lib/antora/extensions/autoconfig-partial-build.js - ./lib/antora/extensions/inject-collector-config.js - '@antora/collector-extension' - ./lib/antora/extensions/version-fix.js + - '@antora/atlas-extension' - '@opendevise/antora-release-line-extension' site: title: Spring Security diff --git a/build.gradle b/build.gradle index 962af95b60..ac8fc60454 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { } antora { - version = '3.2.0-alpha.1' + version = '3.2.0-alpha.2' options = ['--clean', '--fetch', '--stacktrace'] environment = [ 'ALGOLIA_API_KEY': '82c7ead946afbac3cf98c32446154691', @@ -12,7 +12,8 @@ antora { 'ALGOLIA_INDEX_NAME': 'security-docs' ] dependencies = [ + '@antora/atlas-extension': '1.0.0-alpha.1', '@antora/collector-extension': '1.0.0-alpha.2', - '@opendevise/antora-release-line-extension': '1.0.0-alpha.1' + '@opendevise/antora-release-line-extension': '1.0.0-alpha.2' ] } diff --git a/lib/antora/extensions/autoconfig-partial-build.js b/lib/antora/extensions/autoconfig-partial-build.js new file mode 100644 index 0000000000..a0641492fd --- /dev/null +++ b/lib/antora/extensions/autoconfig-partial-build.js @@ -0,0 +1,55 @@ +'use strict' + +const execFile = require('node:util').promisify(require('node:child_process').execFile) +const { promises: fsp } = require('node:fs') + +module.exports.register = function () { + if (!process.env.BUILD_REFNAME) return + + this.once('playbookBuilt', async ({ playbook }) => { + const { concat: get } = this.require('simple-get') + const asciidocAttrs = ((playbook.asciidoc ||= {}).attributes ||= {}) + const siteManifestUrl = asciidocAttrs['primary-site-manifest-url'] || `${playbook.site.url}/site-manifest.json` + const siteManifestData = await (siteManifestUrl.startsWith('https://') + ? download(get, siteManifestUrl) + : fsp.readFile(siteManifestUrl) + ).then(JSON.parse) + let { BUILD_REFNAME: refname, BUILD_VERSION: version } = process.env + const isBranch = /[a-z]$/.test(refname) + if (!version) { + const repoUrl = await execFile('git', ['remote', 'get-url', 'origin']).then(({ stdout: output }) => output.trim()) + const propertiesUrl = `${repoUrl.replace('github.com', 'raw.githubusercontent.com')}/${refname}/gradle.properties` + version = await download(get, propertiesUrl) + .then((contents) => contents.toString().split('\n').find((it) => it.startsWith('version='))?.slice(8)) + } + if (isBranch && version.endsWith('-SNAPSHOT')) version = version.slice(0, -9) + const versionsInManifest = siteManifestData.components.ROOT.versions + if (!(version in versionsInManifest && isBranch === !!versionsInManifest[version].prerelease)) { + const category = require('path').basename(module.id, '.js') + this.getLogger(category).info(`version ${version} not previously built; reverting to full build`) + return + } + Object.assign( + playbook.content.sources[0], + isBranch ? { branches: [refname], tags: [] } : { branches: [], tags: [refname] } + ) + Object.assign( + asciidocAttrs, + { 'primary-site-url': '.', 'primary-site-manifest-url': siteManifestUrl } + ) + this.updateVariables({ playbook }) + }) +} + +function download (get, url) { + return new Promise((resolve, reject) => + get({ url }, (err, response, contents) => { + if (err) reject(err) + if (response.statusCode !== 200) { + const message = `Response code ${response.statusCode} (${response.statusMessage})` + return reject(Object.assign(new Error(message), { name: 'HTTPError' })) + } + resolve(contents) + }) + ) +}