Skip to content

Migrate documentation from Doxygen to Antora + MrDocs#224

Open
steve-downey wants to merge 47 commits intobemanproject:mainfrom
steve-downey:docs/antora-migration
Open

Migrate documentation from Doxygen to Antora + MrDocs#224
steve-downey wants to merge 47 commits intobemanproject:mainfrom
steve-downey:docs/antora-migration

Conversation

@steve-downey
Copy link
Copy Markdown
Member

Summary

Replaces the Doxygen-based documentation toolchain with Antora +
MrDocs. MrDocs generates the C++ API reference pages from the headers;
Antora assembles them with the hand-written narrative pages into a
static site.

What changed

Documentation content

  • New narrative pages: Home, Design & Motivation, Getting Started,
    Examples (replacing docs/overview.md and the Doxygen stubs)
  • Structured navigation in docs/modules/ROOT/nav.adoc
  • Antora component descriptor (docs/antora.yml) and MrDocs config
    (docs/mrdocs.yml)
  • Removed Doxygen assets (CSS, JS, header HTML, .dox files)
    Title:

Migrate documentation from Doxygen to Antora + MrDocs

Body:

Summary

Replaces the Doxygen-based documentation toolchain with Antora +
MrDocs. MrDocs generates the C++ API reference pages from the headers;
Antora assembles them with the hand-written narrative pages into a
static site.

What changed

Documentation content

  • New narrative pages: Home, Design & Motivation, Getting Started,
    Examples (replacing docs/overview.md and the Doxygen stubs)
  • Structured navigation in docs/modules/ROOT/nav.adoc
  • Antora component descriptor (docs/antora.yml) and MrDocs config
    (docs/mrdocs.yml)
  • Removed Doxygen assets (CSS, JS, header HTML, .dox files)

Build system

  • package.json / package-lock.json for Antora and the
    @cppalliance/antora-cpp-reference-extension
  • etc/install-mrdocs.sh — downloads the MrDocs binary
  • Makefile targets: docs, mrdocs, install-antora, install-mrdocs,
    update-antora, update-mrdocs, clean-docs, clean-mrdocs,
    realclean, view-docs; all hooked into the standard clean /
    realclean / install-tools targets
  • antora-playbook.yml and antora-worktree-fix.js — the playbook
    configures the site; the extension makes the build work transparently
    in any checkout layout (normal clone, linked worktree, bare-repo +
    worktrees)

CI

  • docs.yml rewritten: triggers on every push and every PR, not just
    main; uses make docs so MRDOCS_ROOT is set correctly; caches
    MrDocs and node_modules; uploads the built site as a downloadable
    artifact; posts (and updates) a PR comment linking to the artifact so
    reviewers can inspect the rendered docs; deploys to GitHub Pages on
    push to main

Known issue

@cppalliance/antora-cpp-reference-extension 0.1.0 cannot parse
MrDocs 0.8.0's version string (MrDocs version X.Y.Z vs the expected
version: X.Y.Z), producing one unresolved xref to the _
union-sentinel member in optional<T>. The site still builds.
Tracked upstream at https://github.com/cppalliance/antora-cpp-reference-extension

Test plan

  • make docs from a clean worktree produces a site with no errors
    other than the known _ xref
  • make realclean && make docs reinstalls tools and rebuilds from
    scratch
  • Open the built index.html and verify Home, Design & Motivation,
    Getting Started, Examples, and API Reference pages all render and
    link correctly
  • Verify PR CI posts a docs-preview comment with a link to the
    artifact

steve-downey and others added 30 commits May 6, 2026 14:29
Replaces the Doxygen-based doc pipeline with Antora for site generation
and MrDocs for API reference extraction. Hand-written content is in
docs/modules/ROOT/pages/; generated reference pages are gitignored and
produced during CI by the @cppalliance/antora-cpp-reference-extension.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Adds install-tools / update-tools (and individual install-mrdocs,
update-mrdocs, install-antora, update-antora) so the docs toolchain
can be bootstrapped without assuming MrDocs or Antora are already
present. MrDocs is downloaded from GitHub releases into .tools/mrdocs/;
Antora and the cpp-reference extension are installed via npm ci into
node_modules/. Both are tracked as file targets so Make only
re-installs when inputs change.

MRDOCS_VERSION can be set to pin a specific release (default: latest).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Generated artifacts (build/site from Antora, docs/modules/ROOT/pages/reference
from MrDocs) now have dedicated clean-X targets wired into the main clean goal.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Asset name is MrDocs-{version}-{OS}.tar.gz, not the arch/clang-Release
form I had assumed. Since the version is embedded in the filename the
GitHub latest redirect cannot be used; resolve the tag via the GitHub
API at install time instead.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Remove hardcoded clang++-18 from mrdocs.yml cmake args; CXX is now
  detected at build time so local environments don't need that exact version
- Makefile detects available clang++ (tries versioned names 18-21 then generic)
  and passes it as CXX to both the docs and mrdocs targets
- Use MRDOCS_ROOT env var so the antora-cpp-reference-extension uses our
  locally installed MrDocs instead of calling the GitHub API (which is
  blocked in some environments)
- Simplify CI: use make install-mrdocs / make docs instead of separate
  manual steps with the old wrong download URL

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- index.adoc and nav.adoc used xref:reference/index.adoc (path syntax)
  but the cpp-reference extension places generated pages in a separate
  Antora module named 'reference'; the correct cross-module syntax is
  xref:reference:index.adoc (module:page syntax)
- Remove beman::optional::optional::_ from exclude-symbols: extract-private
  is already false, and explicit exclusion doesn't prevent MrDocs generating
  a link to it in the parent class page anyway (extension 0.1.0 bug)

Known issue: @cppalliance/antora-cpp-reference-extension 0.1.0 cannot
parse MrDocs 0.8.0's version string ("MrDocs version X.Y.Z" vs the
expected "version: X.Y.Z" format), causing it to register multipage
output at a doubled virtual path. This produces one unresolved xref
to the _ union variant member in optional-03; the site still builds.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ility issue

The Antora + MrDocs pipeline is modelled on the approach used by Boost
libraries (boostorg/url). Added comments crediting that work and pointing
to the upstream repo, so future maintainers can track fixes there.

Documents the known issue with antora-cpp-reference-extension 0.1.0 +
MrDocs 0.8.0: the extension cannot parse the new version string format
("MrDocs version X.Y.Z" vs "version: X.Y.Z"), causing one unresolved
xref to the _ union-sentinel member. 0.1.0 is the latest release of the
extension; Boost libraries are on the same version and have the same
behaviour. Track fixes at https://github.com/cppalliance/antora-cpp-reference-extension

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Using build/site as a Make target is unreliable because antora overwrites
files inside it without updating the directory's own mtime. Replace with:

- DOCS_STAMP (build/site/.stamp): touched after every successful build;
  Make compares this regular file against prerequisites correctly.
- DOCS_DEPS (build/site/.docs.d): generated post-build in the style of
  gcc -MMD -MP — one "stamp: file" dependency line per .hpp / .adoc source,
  plus a phony target per file so deleted files do not cause errors on the
  next run. Included with -include so it is silently absent on first build.

An explicit empty rule for DOCS_DEPS prevents the -include from falling
through to the .DEFAULT cmake passthrough when the file is missing.
Both files live inside build/site/ so clean-docs removes them automatically.

Result: `make docs` is a no-op when nothing has changed, and correctly
rebuilds when any header, adoc page, or config file is newer than the stamp.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Several recipes use bash-specific syntax (if/then/else with parameter
expansion like \${tag#v}, for-loop with command -v, brace grouping).
Setting SHELL explicitly ensures they work regardless of the user's
login shell or environment.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
A generic .stamp name is ambiguous if more stamp files are added
alongside it. .docs.stamp makes the purpose clear.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Follows the same pattern as PYEXECPATH detection. Emits a clear
$(error ...) if bash is not in PATH rather than failing later with a
confusing recipe error.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
which is for cascading version searches (as with PYEXECPATH); command -v
is the correct POSIX idiom for locating a single named executable.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Antora site output moves from build/site to $(_build_path)/site so it
is co-located with the compilation database for that toolchain and the
root-level compile_commands.json symlink (which may point elsewhere)
is never consulted. --to-dir overrides antora-playbook.yml's output.dir,
preserving a sensible default for standalone npx antora invocations.

Adds print-docs-out target so CI can locate the built site without
hardcoding the path. The deploy step queries it via make -s print-docs-out
and passes the result to peaceiris/actions-gh-pages as publish_dir.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The $(MRDOCS) recipe was 11 lines; per the housekeeping rule any recipe
over 8 lines becomes a script. etc/install-mrdocs.sh takes all values as
explicit parameters (--version, --install-dir, --os) so it does not rely
on Make having set the environment, and is safe to run standalone.

Script features:
- set -euo pipefail
- --help / usage text
- error check on empty tag when resolving 'latest'
- printf throughout (shellcheck-clean, verified)
- auto-detects OS if --os is not passed

The Makefile recipe shrinks to 3 lines passing all variables explicitly.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Bumps the github-actions group with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [step-security/harden-runner](https://github.com/step-security/harden-runner) | `2.19.0` | `2.19.1` |
| [bemanproject/infra-workflows/.github/workflows/reusable-beman-submodule-check.yml](https://github.com/bemanproject/infra-workflows) | `1.5.3` | `1.7.1` |
| [bemanproject/infra-workflows/.github/workflows/reusable-beman-preset-test.yml](https://github.com/bemanproject/infra-workflows) | `1.5.3` | `1.7.1` |
| [bemanproject/infra-workflows/.github/workflows/reusable-beman-build-and-test.yml](https://github.com/bemanproject/infra-workflows) | `1.5.3` | `1.7.1` |
| [bemanproject/infra-workflows/.github/workflows/reusable-beman-create-issue-when-fault.yml](https://github.com/bemanproject/infra-workflows) | `1.5.3` | `1.7.1` |
| [bemanproject/infra-workflows/.github/workflows/reusable-beman-pre-commit.yml](https://github.com/bemanproject/infra-workflows) | `1.5.3` | `1.7.1` |
| [bemanproject/infra-workflows/.github/workflows/reusable-beman-update-pre-commit.yml](https://github.com/bemanproject/infra-workflows) | `1.5.3` | `1.7.1` |

Updates `step-security/harden-runner` from 2.19.0 to 2.19.1
- [Release notes](https://github.com/step-security/harden-runner/releases)
- [Commits](step-security/harden-runner@8d3c67d...a5ad31d)

Updates `bemanproject/infra-workflows/.github/workflows/reusable-beman-submodule-check.yml` from 1.5.3 to 1.7.1
- [Commits](bemanproject/infra-workflows@503ac65...4d946e2)

Updates `bemanproject/infra-workflows/.github/workflows/reusable-beman-preset-test.yml` from 1.5.3 to 1.7.1
- [Commits](bemanproject/infra-workflows@503ac65...4d946e2)

Updates `bemanproject/infra-workflows/.github/workflows/reusable-beman-build-and-test.yml` from 1.5.3 to 1.7.1
- [Commits](bemanproject/infra-workflows@503ac65...4d946e2)

Updates `bemanproject/infra-workflows/.github/workflows/reusable-beman-create-issue-when-fault.yml` from 1.5.3 to 1.7.1
- [Commits](bemanproject/infra-workflows@503ac65...4d946e2)

Updates `bemanproject/infra-workflows/.github/workflows/reusable-beman-pre-commit.yml` from 1.5.3 to 1.7.1
- [Commits](bemanproject/infra-workflows@503ac65...4d946e2)

Updates `bemanproject/infra-workflows/.github/workflows/reusable-beman-update-pre-commit.yml` from 1.5.3 to 1.7.1
- [Commits](bemanproject/infra-workflows@503ac65...4d946e2)

---
updated-dependencies:
- dependency-name: step-security/harden-runner
  dependency-version: 2.19.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: bemanproject/infra-workflows/.github/workflows/reusable-beman-submodule-check.yml
  dependency-version: 1.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: bemanproject/infra-workflows/.github/workflows/reusable-beman-preset-test.yml
  dependency-version: 1.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: bemanproject/infra-workflows/.github/workflows/reusable-beman-build-and-test.yml
  dependency-version: 1.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: bemanproject/infra-workflows/.github/workflows/reusable-beman-create-issue-when-fault.yml
  dependency-version: 1.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: bemanproject/infra-workflows/.github/workflows/reusable-beman-pre-commit.yml
  dependency-version: 1.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: bemanproject/infra-workflows/.github/workflows/reusable-beman-update-pre-commit.yml
  dependency-version: 1.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the github-owned-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action).


Updates `github/codeql-action` from 4.35.2 to 4.35.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@95e58e9...e46ed2c)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-owned-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
The default Antora UI bundle ships placeholder "Products / Services /
Download" nav items. Replace them via a supplemental UI partial
(supplemental-ui/partials/header-content.hbs) which overrides only
the header-content partial, leaving all other UI templates intact:

  - Brand: beman.optional → site home (unchanged, from {{site.title}})
  - Beman Project → https://bemanproject.github.io
  - Libraries → https://github.com/bemanproject  (org library listing)
  - GitHub button → https://github.com/bemanproject/optional

The page-versions.hbs partial in the default UI already renders a
version dropdown in the toolbar whenever page.versions is populated.
To activate it, add release tags alongside HEAD in antora-playbook.yml:

  branches: [HEAD, v1.0, v1.1]

Each referenced ref must carry a docs/antora.yml with the corresponding
version: field. The comment in antora-playbook.yml documents this.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replaces the Doxygen-based doc pipeline with Antora for site generation
and MrDocs for API reference extraction. Hand-written content is in
docs/modules/ROOT/pages/; generated reference pages are gitignored and
produced during CI by the @cppalliance/antora-cpp-reference-extension.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Adds install-tools / update-tools (and individual install-mrdocs,
update-mrdocs, install-antora, update-antora) so the docs toolchain
can be bootstrapped without assuming MrDocs or Antora are already
present. MrDocs is downloaded from GitHub releases into .tools/mrdocs/;
Antora and the cpp-reference extension are installed via npm ci into
node_modules/. Both are tracked as file targets so Make only
re-installs when inputs change.

MRDOCS_VERSION can be set to pin a specific release (default: latest).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Generated artifacts (build/site from Antora, docs/modules/ROOT/pages/reference
from MrDocs) now have dedicated clean-X targets wired into the main clean goal.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Asset name is MrDocs-{version}-{OS}.tar.gz, not the arch/clang-Release
form I had assumed. Since the version is embedded in the filename the
GitHub latest redirect cannot be used; resolve the tag via the GitHub
API at install time instead.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Remove hardcoded clang++-18 from mrdocs.yml cmake args; CXX is now
  detected at build time so local environments don't need that exact version
- Makefile detects available clang++ (tries versioned names 18-21 then generic)
  and passes it as CXX to both the docs and mrdocs targets
- Use MRDOCS_ROOT env var so the antora-cpp-reference-extension uses our
  locally installed MrDocs instead of calling the GitHub API (which is
  blocked in some environments)
- Simplify CI: use make install-mrdocs / make docs instead of separate
  manual steps with the old wrong download URL

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- index.adoc and nav.adoc used xref:reference/index.adoc (path syntax)
  but the cpp-reference extension places generated pages in a separate
  Antora module named 'reference'; the correct cross-module syntax is
  xref:reference:index.adoc (module:page syntax)
- Remove beman::optional::optional::_ from exclude-symbols: extract-private
  is already false, and explicit exclusion doesn't prevent MrDocs generating
  a link to it in the parent class page anyway (extension 0.1.0 bug)

Known issue: @cppalliance/antora-cpp-reference-extension 0.1.0 cannot
parse MrDocs 0.8.0's version string ("MrDocs version X.Y.Z" vs the
expected "version: X.Y.Z" format), causing it to register multipage
output at a doubled virtual path. This produces one unresolved xref
to the _ union variant member in optional-03; the site still builds.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…ility issue

The Antora + MrDocs pipeline is modelled on the approach used by Boost
libraries (boostorg/url). Added comments crediting that work and pointing
to the upstream repo, so future maintainers can track fixes there.

Documents the known issue with antora-cpp-reference-extension 0.1.0 +
MrDocs 0.8.0: the extension cannot parse the new version string format
("MrDocs version X.Y.Z" vs "version: X.Y.Z"), causing one unresolved
xref to the _ union-sentinel member. 0.1.0 is the latest release of the
extension; Boost libraries are on the same version and have the same
behaviour. Track fixes at https://github.com/cppalliance/antora-cpp-reference-extension

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Using build/site as a Make target is unreliable because antora overwrites
files inside it without updating the directory's own mtime. Replace with:

- DOCS_STAMP (build/site/.stamp): touched after every successful build;
  Make compares this regular file against prerequisites correctly.
- DOCS_DEPS (build/site/.docs.d): generated post-build in the style of
  gcc -MMD -MP — one "stamp: file" dependency line per .hpp / .adoc source,
  plus a phony target per file so deleted files do not cause errors on the
  next run. Included with -include so it is silently absent on first build.

An explicit empty rule for DOCS_DEPS prevents the -include from falling
through to the .DEFAULT cmake passthrough when the file is missing.
Both files live inside build/site/ so clean-docs removes them automatically.

Result: `make docs` is a no-op when nothing has changed, and correctly
rebuilds when any header, adoc page, or config file is newer than the stamp.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Several recipes use bash-specific syntax (if/then/else with parameter
expansion like \${tag#v}, for-loop with command -v, brace grouping).
Setting SHELL explicitly ensures they work regardless of the user's
login shell or environment.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
A generic .stamp name is ambiguous if more stamp files are added
alongside it. .docs.stamp makes the purpose clear.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Follows the same pattern as PYEXECPATH detection. Emits a clear
$(error ...) if bash is not in PATH rather than failing later with a
confusing recipe error.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
which is for cascading version searches (as with PYEXECPATH); command -v
is the correct POSIX idiom for locating a single named executable.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Antora site output moves from build/site to $(_build_path)/site so it
is co-located with the compilation database for that toolchain and the
root-level compile_commands.json symlink (which may point elsewhere)
is never consulted. --to-dir overrides antora-playbook.yml's output.dir,
preserving a sensible default for standalone npx antora invocations.

Adds print-docs-out target so CI can locate the built site without
hardcoding the path. The deploy step queries it via make -s print-docs-out
and passes the result to peaceiris/actions-gh-pages as publish_dir.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
steve-downey and others added 14 commits May 7, 2026 18:21
The $(MRDOCS) recipe was 11 lines; per the housekeeping rule any recipe
over 8 lines becomes a script. etc/install-mrdocs.sh takes all values as
explicit parameters (--version, --install-dir, --os) so it does not rely
on Make having set the environment, and is safe to run standalone.

Script features:
- set -euo pipefail
- --help / usage text
- error check on empty tag when resolving 'latest'
- printf throughout (shellcheck-clean, verified)
- auto-detects OS if --os is not passed

The Makefile recipe shrinks to 3 lines passing all variables explicitly.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replaces the Doxygen-based doc pipeline with Antora for site generation
and MrDocs for API reference extraction. Hand-written content is in
docs/modules/ROOT/pages/; generated reference pages are gitignored and
produced during CI by the @cppalliance/antora-cpp-reference-extension.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Remove hardcoded clang++-18 from docs/mrdocs.yml so MrDocs inherits
the CXX env var. Update Makefile to derive _docs_cxx from TOOLCHAIN
when a versioned clang toolchain is active (e.g. TOOLCHAIN=clang-21
yields clang++-21), falling back to auto-detecting the newest
available clang++. Also switch clang-flags.cmake to libstdc++.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
branches: [HEAD] reads from git objects (committed content), so Antora
fails or sees stale content when invoked from a linked git worktree.
worktrees: [HEAD] reads from the filesystem directly, which works in
any worktree and also picks up uncommitted changes during local editing.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Antora 3.1 checks whether .git is a directory to detect a git repo.
In a linked worktree .git is a *file* (a gitdir reference), so Antora
falls back to treating the directory as a bare repo and then fails to
resolve HEAD, producing "Local content source must be a git repository".

Add antora-worktree-fix.js, a playbookBuilt extension that reads the
.git file, follows the gitdir reference to find the main repo root,
and rewrites the content source url to that root.  It also replaces any
literal "HEAD" branch pattern with the branch actually checked out in
the linked worktree.  This makes branches: [HEAD] work transparently
in both normal checkouts and linked worktrees.

Revert worktrees: [HEAD] (which does not do what was intended — it
filters linked-worktree names, not HEAD itself) back to branches: [HEAD].
Worktree mode remains available for users who configure it explicitly.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
output.dir was build/site (no dot prefix), inconsistent with the project
convention that all build artifacts live under .build/.  The Makefile
already overrides this with --to-dir for toolchain-specific builds; the
change only affects direct npx antora invocations.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…syntax

Use node_modules/.package-lock.json (written by npm ci) as the Make
sentinel so an empty node_modules directory no longer fools timestamp
checks.  Add package.json as a dependency alongside package-lock.json.

Make `docs` and `mrdocs` depend on install-antora/install-mrdocs so
a plain `make docs` auto-installs tools rather than failing mid-build.

Hook clean-docs into realclean so `make realclean` removes the built
site alongside the installed tools.

Fix the API Reference xref in index.adoc: the cpp-reference-extension
registers MrDocs output in a separate Antora module named `reference`,
so the cross-module xref syntax `reference:index.adoc` (colon) is
required rather than `reference/index.adoc` (slash, which resolves
within the ROOT module's pages directory).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
When the git repo is a bare repo (e.g. optional.git) with worktrees
checked out alongside it, mainGitdir resolves to the bare repo directory
itself.  path.dirname(mainGitdir) then gives the plain parent directory
which has no git content, causing Antora to report "Local content source
must be a git repository: <parent>".

Fix: read core.bare from mainGitdir/config.  If true, use mainGitdir
directly as the content source URL (Antora/isomorphic-git can read bare
repos).  Also handle the core.worktree case for repos with a separate
git dir and explicit working tree.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Merge 82796c0 clobbered two fixes from the local branch (460b35b):

1. nav.adoc was emptied by the merge; restore the navigation list with
   the correct cross-module xref syntax (reference:index.adoc, colon)
   rather than the path syntax (reference/index.adoc, slash) that the
   earlier commit had also fixed.

2. Remove beman::optional::optional::_ from exclude-symbols in
   mrdocs.yml.  extract-private: false already prevents the _ union
   sentinel from being documented; the explicit exclusion does not
   suppress the xref MrDocs emits to it from the parent class page
   (extension 0.1.0 known bug), so the entry has no useful effect.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
branches: [HEAD] reads committed content; in a bare-repo + worktrees
layout the local branch must be up-to-date before building docs.
Add a comment pointing to the git pull step to avoid confusion.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
In a bare-repo + worktrees layout, Antora/isomorphic-git reads
refs/remotes/<remote>/<branch> rather than refs/heads/<branch>.
When the user fetches from a secondary remote (e.g. bbgithub) the
local head moves forward but origin's tracking ref stays behind,
causing Antora to build from stale committed content.

Fix: before Antora aggregates content, read refs/heads/<branch> from
the bare repo and write that SHA to every refs/remotes/*/<branch>
tracking ref that differs.  This ensures Antora always reads the
current local-branch state regardless of fetch history.

Add readRef (loose + packed-refs) and writeRef helpers to support this.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Three cases the extension must cover in a bare-repo + worktrees layout:

1. Branch pushed to origin — refs/remotes/origin/<branch> exists but
   may be stale if origin wasn't last fetched.  Synced by old code.

2. Branch pushed only to a fork remote (e.g. bbgithub) — the origin
   tracking ref doesn't exist at all; Antora can't find the branch.
   Fix: always create/update refs/remotes/origin/<branch> from the
   local head, guaranteeing discoverability regardless of push history.

3. Brand new branch, not pushed anywhere yet — same gap as case 2.
   Same fix covers it.

Other remotes' tracking refs (case 1 variants) are still synced when
they already exist, but we no longer create them for non-origin remotes.

CI (non-bare clone): unaffected — extension exits early when .git is
a directory, Antora reads the pushed commit natively.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Previous workflow only triggered on pushes to main, ran npx antora
directly without MRDOCS_ROOT (causing the extension to re-download
MrDocs), and used a hardcoded wrong output path.

Changes:
- Trigger on all pushes and all PRs so every branch and PR gets a
  docs build, not just main.
- Use `make docs` throughout: it sets MRDOCS_ROOT correctly, handles
  npm ci, and auto-detects the clang compiler.
- Cache .tools/mrdocs (keyed on install script hash) and node_modules
  (keyed on package-lock.json hash) to speed up repeated runs.
- Capture the output path with `make -s print-docs-out` so the
  artifact upload and gh-pages deploy always use the right directory.
- Upload the built site as a docs-site artifact (14-day retention) on
  every run so any branch build is downloadable for inspection.
- Post a PR comment with a link to the workflow run and instructions
  for downloading and opening the artifact.  The comment is updated
  (not duplicated) on subsequent pushes to the same PR.
  continue-on-error so fork PRs without write permission don't fail CI.
- Keep the GitHub Pages deploy step for pushes to main.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant