diff --git a/antora-playbook.yml b/antora-playbook.yml index 87141ef60b2..065cd5ca72d 100644 --- a/antora-playbook.yml +++ b/antora-playbook.yml @@ -41,6 +41,29 @@ content: - url: ./ start_path: openidm edit_url: https://github.com/OpenIdentityPlatform/OpenIDM/edit/master/openidm-doc/src/main/asciidoc + # Older versions: the last release of each previous major line, from the tags the product release + # workflows put on this repository. One tag per source; lib/versions-from-tags.js reads the tag + # (fetching it from origin if missing) and turns it into the version: OpenAM-15.2.2 -> 15.2. + - url: ./ + start_path: opendj + branches: ~ + tags: OpenDJ-4.10.2 + edit_url: false + - url: ./ + start_path: openig + branches: ~ + tags: OpenIG-5.3.2 + edit_url: false + - url: ./ + start_path: openam + branches: ~ + tags: OpenAM-15.2.2 + edit_url: false + - url: ./ + start_path: openidm + branches: ~ + tags: OpenIDM-6.3.0 + edit_url: false ui: bundle: url: https://gitlab.com/antora/antora-ui-default/-/jobs/artifacts/HEAD/raw/build/ui-bundle.zip?job=bundle-stable @@ -52,6 +75,7 @@ output: antora: extensions: + - ./lib/versions-from-tags.js - ./lib/add-pdf-link.js diff --git a/docsearch/config.json b/docsearch/config.json index 7c8c40c280c..18f94a128b4 100644 --- a/docsearch/config.json +++ b/docsearch/config.json @@ -39,7 +39,8 @@ "https://doc.openidentityplatform.org/openig/apidocs", "https://doc.openidentityplatform.org/commons/apidocs", "https://doc.openidentityplatform.org/openicf/apidocs", - "https://doc.openidentityplatform.org/openidm/apidocs" + "https://doc.openidentityplatform.org/openidm/apidocs", + "https://doc.openidentityplatform.org/[a-z]+/[0-9]+\\.[0-9]+/" ], "selectors": { "default": { diff --git a/lib/add-pdf-link.js b/lib/add-pdf-link.js index a6503129767..eed729a475f 100644 --- a/lib/add-pdf-link.js +++ b/lib/add-pdf-link.js @@ -1,3 +1,18 @@ +/* + * The contents of this file are subject to the terms of the Common Development and + * Distribution License (the License). You may not use this file except in compliance with the + * License. + * + * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the + * specific language governing permission and limitations under the License. + * + * When distributing Covered Software, include this CDDL Header Notice in each file and include + * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL + * Header, with the fields enclosed by brackets [] replaced by your own identifying + * information: "Portions copyright [year] [name of copyright owner]". + * + * Copyright 2024-2026 3A Systems, LLC. + */ module.exports.register = function () { this.on('navigationBuilt', ({contentCatalog}) => { @@ -9,7 +24,8 @@ module.exports.register = function () { }); contentCatalog.getFiles().forEach((file) => { - if(file.asciidoc && file.asciidoc.attributes) { + // the PDFs are built from the current sources, so older versions get no PDF link + if(file.asciidoc && file.asciidoc.attributes && file.src.version === contentCatalog.getComponent(file.src.component)?.latest?.version) { if(compomentsPdfs[file.src.component] && compomentsPdfs[file.src.component][file.src.module]) { const pdfLink = compomentsPdfs[file.src.component][file.src.module]; file.asciidoc.attributes['page-pdflink'] = pdfLink; diff --git a/lib/versions-from-tags.js b/lib/versions-from-tags.js new file mode 100644 index 00000000000..875d2541e4d --- /dev/null +++ b/lib/versions-from-tags.js @@ -0,0 +1,105 @@ +/* + * The contents of this file are subject to the terms of the Common Development and + * Distribution License (the License). You may not use this file except in compliance with the + * License. + * + * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the + * specific language governing permission and limitations under the License. + * + * When distributing Covered Software, include this CDDL Header Notice in each file and include + * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL + * Header, with the fields enclosed by brackets [] replaced by your own identifying + * information: "Portions copyright [year] [name of copyright owner]". + * + * Copyright 2026 3A Systems, LLC. + */ + +'use strict' + +// Publishes release tags of this repository (OpenAM-15.2.2 etc.) as older versions of a component. +// +// A content source that names a tag is not read by Antora from the git tree, for two reasons: +// - the antora.yml of every tag declares `version: ~`, and Antora gives the version in antora.yml +// precedence over the version of the content source, so the tag would be merged into the +// unversioned component version built from the branch; +// - Antora reads every file under the start path of a git tree, and the start path of a tag also +// holds the API docs of that time (18,672 files for OpenAM-15.2.2, against 330 pages), which +// makes the build several times slower. +// Instead, only antora.yml and modules/ of the tag are extracted with `git archive` into a +// temporary repository, which is aggregated apart from the other sources, and the result is given +// the version of the tag: OpenAM-15.2.2 becomes version 15.2, displayed as 15.2.2. The branch +// stays the unversioned (and latest) version, so its URLs do not change. +// The temporary repositories are kept at a fixed path, build/antora-tags/, because Antora logs +// the files of a tag with that path, and .github/build-baseline keys the known errors by it. + +const { execFileSync } = require('child_process') +const fs = require('fs') +const ospath = require('path') + +const TAG_RX = /^[^-]+-(\d+)\.(\d+)\.(\d+)$/ + +module.exports.register = function () { + const logger = this.getLogger('versions-from-tags') + this.replaceFunctions({ + async aggregateContent (playbook) { + const aggregateContent = this.require('@antora/content-aggregator') + const sources = playbook.content.sources + const withSources = (subset) => ({ ...playbook, content: { ...playbook.content, sources: subset } }) + const aggregate = await aggregateContent(withSources(sources.filter((source) => !source.tags))) + const tmpdir = ospath.join(playbook.dir, 'build', 'antora-tags') + fs.rmSync(tmpdir, { recursive: true, force: true }) + fs.mkdirSync(tmpdir, { recursive: true }) + try { + for (const source of sources.filter((source) => source.tags)) { + const tag = source.tags + const match = typeof tag === 'string' && tag.match(TAG_RX) + if (!match) throw new Error(`content source ${source.startPath}: tags must name one release tag, got ${tag}`) + const worktree = ospath.join(tmpdir, tag) + extractTag(ospath.resolve(playbook.dir, source.url), tag, source.startPath, worktree, logger) + const tagSource = { url: worktree, branches: 'HEAD', startPath: source.startPath, editUrl: source.editUrl } + for (const componentVersion of await aggregateContent(withSources([tagSource]))) { + componentVersion.version = `${match[1]}.${match[2]}` + componentVersion.displayVersion = `${match[1]}.${match[2]}.${match[3]}` + logger.info('%s %s from tag %s', componentVersion.name, componentVersion.version, tag) + aggregate.push(componentVersion) + } + } + } finally { + fs.rmSync(tmpdir, { recursive: true, force: true }) + } + return aggregate + }, + }) +} + +// Extracts antora.yml and modules/ of startPath at tag into a new single-commit repository. +// Fetches the tag from origin first if the repository does not have it, as in a CI checkout. +function extractTag (repo, tag, startPath, worktree, logger) { + const git = (dir, ...args) => execFileSync('git', ['-C', dir, ...args], { encoding: 'utf8', stdio: 'pipe' }) + try { + git(repo, 'rev-parse', '-q', '--verify', `refs/tags/${tag}^{commit}`) + } catch { + logger.info('fetching tag %s', tag) + const shallow = git(repo, 'rev-parse', '--is-shallow-repository').trim() === 'true' + try { + git(repo, 'fetch', '-q', '--no-tags', ...(shallow ? ['--depth=1'] : []), 'origin', `+refs/tags/${tag}:refs/tags/${tag}`) + } catch (err) { + // e.g. a clone of a fork created before the tag was pushed, or no network + throw new Error(`cannot fetch tag ${tag} from the origin of ${repo}; if the tag is missing there, run ` + + `git fetch https://github.com/OpenIdentityPlatform/doc.openidentityplatform.org tag ${tag}\n${err.stderr || err.message}`) + } + } + fs.mkdirSync(worktree) + const paths = [`${startPath}/antora.yml`, `${startPath}/modules`] + const archive = execFileSync('git', ['-C', repo, 'archive', '--format=tar', tag, '--', ...paths], { + maxBuffer: 1024 * 1024 * 1024, + }) + // -f -: without it tar reads the archive from $TAPE or a system-dependent default device + execFileSync('tar', ['-x', '-f', '-', '-C', worktree], { input: archive }) + // the branch is named after the tag, so that Antora logs the tag as the refname of its files + git(worktree, 'init', '-q', '-b', tag) + git(worktree, 'add', '-A') + // no hooks: a global core.hooksPath or init.templateDir hook of the developer may reject the commit + git(worktree, '-c', 'user.name=antora', '-c', 'user.email=antora@localhost', '-c', 'commit.gpgsign=false', + '-c', 'core.hooksPath=/dev/null', 'commit', '-q', '-m', tag) +} diff --git a/openam/antora.yml b/openam/antora.yml index c4c5f4ee64b..dadacfee15f 100644 --- a/openam/antora.yml +++ b/openam/antora.yml @@ -10,11 +10,12 @@ # Header, with the fields enclosed by brackets [] replaced by your own identifying # information: "Portions copyright [year] [name of copyright owner]". # -# Portions Copyright 2026 3A Systems, LLC. +# Copyright 2024-2026 3A Systems, LLC. name: openam title: 'OpenAM: Access Management' version: ~ +display_version: '16.x' asciidoc: attributes: pdfs: diff --git a/opendj/antora.yml b/opendj/antora.yml index 38d5826055e..f1a2bf9381b 100644 --- a/opendj/antora.yml +++ b/opendj/antora.yml @@ -1,6 +1,21 @@ +# The contents of this file are subject to the terms of the Common Development and +# Distribution License (the License). You may not use this file except in compliance with the +# License. +# +# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the +# specific language governing permission and limitations under the License. +# +# When distributing Covered Software, include this CDDL Header Notice in each file and include +# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL +# Header, with the fields enclosed by brackets [] replaced by your own identifying +# information: "Portions copyright [year] [name of copyright owner]". +# +# Copyright 2024-2026 3A Systems, LLC. + name: opendj title: 'OpenDJ: Directory Services' version: ~ +display_version: '5.x' asciidoc: attributes: pdfs: diff --git a/openidm/antora.yml b/openidm/antora.yml index c6ab768d8eb..7df0719c8fc 100644 --- a/openidm/antora.yml +++ b/openidm/antora.yml @@ -1,6 +1,21 @@ +# The contents of this file are subject to the terms of the Common Development and +# Distribution License (the License). You may not use this file except in compliance with the +# License. +# +# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the +# specific language governing permission and limitations under the License. +# +# When distributing Covered Software, include this CDDL Header Notice in each file and include +# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL +# Header, with the fields enclosed by brackets [] replaced by your own identifying +# information: "Portions copyright [year] [name of copyright owner]". +# +# Copyright 2024-2026 3A Systems, LLC. + name: openidm title: 'OpenIDM: Identity Management' version: ~ +display_version: '7.x' asciidoc: attributes: pdfs: diff --git a/openig/antora.yml b/openig/antora.yml index d8f2c2b04d8..13360ebbece 100644 --- a/openig/antora.yml +++ b/openig/antora.yml @@ -1,6 +1,21 @@ +# The contents of this file are subject to the terms of the Common Development and +# Distribution License (the License). You may not use this file except in compliance with the +# License. +# +# You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the +# specific language governing permission and limitations under the License. +# +# When distributing Covered Software, include this CDDL Header Notice in each file and include +# the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL +# Header, with the fields enclosed by brackets [] replaced by your own identifying +# information: "Portions copyright [year] [name of copyright owner]". +# +# Copyright 2024-2026 3A Systems, LLC. + name: openig title: 'OpenIG: Identity Gateway' version: ~ +display_version: '6.x' #start_page: gateway-guide:preface.adoc asciidoc: attributes: