diff --git a/.github/workflows/publish_wiki.yml b/.github/workflows/publish_wiki.yml new file mode 100644 index 0000000..724a3bd --- /dev/null +++ b/.github/workflows/publish_wiki.yml @@ -0,0 +1,62 @@ +name: publish wiki docs + +on: + push: + branches: + - "main" + paths: + - "src/nxlib/**" + - "scripts/generate_md_docs.py" + workflow_dispatch: + pull_request: + +permissions: + contents: write + +jobs: + publish-wiki: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Install uv + uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6 + + - name: Install nxlib and dev dependencies + run: uv sync --dev + + - name: Generate Markdown docs + run: uv run python scripts/generate_md_docs.py docs_md + + - name: Publish to wiki + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git clone "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.wiki.git" wiki_repo + + find wiki_repo -mindepth 1 ! -path 'wiki_repo/.git' ! -path 'wiki_repo/.git/*' -delete + + # Copy with flat names (wiki doesn't support path links), rewrite ](a/b/c) -> ](a-b-c) + : > wiki_repo/.pages + find docs_md -name '*.md' | sort | while read -r f; do + flat="${f#docs_md/}"; flat="${flat//\//-}" + cp "$f" "wiki_repo/$flat" + perl -i -pe 's/\]\(([^)]+)\)/"](" . ($1 =~ s|\/|-|gr) . ")"/ge' "wiki_repo/$flat" + echo "${flat%.md}" >> wiki_repo/.pages + done + + [ -f wiki_repo/nxlib.md ] && cp wiki_repo/nxlib.md wiki_repo/Home.md + { + echo "### nxlib docs" + echo "" + echo "- [Home](Home)" + sed 's/^\(.*\)$/- [\1](\1)/' wiki_repo/.pages + } > wiki_repo/_Sidebar.md + rm -f wiki_repo/.pages + + cd wiki_repo + git add -A + git diff --cached --quiet || { git commit -m "Update wiki docs from ${GITHUB_SHA::8}"; git push; } diff --git a/.gitignore b/.gitignore index 0fbe32d..3950dc7 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ # mech_data_tools specific typings/ +# generated markdown docs (scripts/generate_md_docs.py) +docs_md/ + # python *.pyc __pycache__ diff --git a/pyproject.toml b/pyproject.toml index 0c18ff2..fdeebd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ where = ["src"] [dependency-groups] dev = [ "pdoc==15.0.4", + "pydoc-markdown>=4.0", "pyright==1.1.403", "pytest==8.4.1", "ruff==0.13.3", diff --git a/scripts/generate_docs.py b/scripts/generate_docs.py index 452bce3..81bdff1 100644 --- a/scripts/generate_docs.py +++ b/scripts/generate_docs.py @@ -82,4 +82,4 @@ def _mock_import(name, globals=[], locals={}, fromlist=[], level=0): pdoc.render.configure(docformat="numpy") # pyright: ignore[reportPrivateImportUsage] # Build the documentation - doc = pdoc.pdoc("nxlib", output_directory=args.build_dir) + pdoc.pdoc("nxlib", output_directory=args.build_dir) diff --git a/scripts/generate_md_docs.py b/scripts/generate_md_docs.py new file mode 100644 index 0000000..dad49bf --- /dev/null +++ b/scripts/generate_md_docs.py @@ -0,0 +1,72 @@ +# Copyright 2026 Commonwealth Fusion Systems (CFS), all rights reserved. +# This entire source code file represents the sole intellectual property of CFS. +# +# 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 +# +# http://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. +"""Generate nxlib API documentation as Markdown using pydoc-markdown. + +Output is written as one .md file per module under the given build directory, +mirroring the package layout (e.g. nxlib/nxopen/uf.md). No import of nxlib +is required (pydoc-markdown parses source via docspec), so NXOpen need not be +installed. +""" + +from __future__ import annotations + +import argparse +from pathlib import Path + +from pydoc_markdown import PydocMarkdown +from pydoc_markdown.contrib.loaders.python import PythonLoader +from pydoc_markdown.contrib.renderers.markdown import MarkdownRenderer + + +def main() -> None: + parser = argparse.ArgumentParser( + "generate_md_docs", + description="Generate nxlib API documentation as Markdown (wiki-friendly).", + ) + parser.add_argument( + "build_dir", + type=Path, + help="Output directory for Markdown files (e.g. docs_md).", + ) + args = parser.parse_args() + + build_dir = args.build_dir.resolve() + build_dir.mkdir(parents=True, exist_ok=True) + + session = PydocMarkdown() + loader = session.loaders[0] + assert isinstance(loader, PythonLoader) + loader.search_path = ["src"] + loader.packages = ["nxlib"] + + modules = session.load_modules() + session.process(modules) + + renderer = session.renderer + assert isinstance(renderer, MarkdownRenderer) + renderer.render_toc = True + renderer.insert_header_anchors = True + + for module in modules: + out_path = build_dir / f"{module.name.replace('.', '/')}.md" + out_path.parent.mkdir(parents=True, exist_ok=True) + md = renderer.render_to_string([module]) + out_path.write_text(md, encoding="utf-8") + + print(f"Wrote {len(modules)} Markdown files under {build_dir}") + + +if __name__ == "__main__": + main()